From db87c342c06c43f43ca1c205b0acc1e45110c732 Mon Sep 17 00:00:00 2001 From: Tim Jacomb Date: Thu, 4 Jan 2024 17:53:30 +0000 Subject: [PATCH 1/2] Split agent templates into multiple pages --- pom.xml | 6 +- .../azure/vmagent/AzureVMAgentTemplate.java | 138 +++- .../microsoft/azure/vmagent/AzureVMCloud.java | 62 +- .../vmagent/AzureVMAgentTemplate/config.jelly | 605 +++++++++--------- .../vmagent/AzureVMAgentTemplate/index.jelly | 40 ++ .../AzureVMAgentTemplate/index.properties | 1 + .../AzureVMAgentTemplate/sidepanel.jelly | 12 + .../AzureVMAgentTemplate/sidepanel.properties | 1 + .../azure/vmagent/AzureVMCloud/config.jelly | 6 +- .../azure/vmagent/AzureVMCloud/new.jelly | 27 + .../vmagent/AzureVMCloud/sidepanel.jelly | 18 + .../vmagent/AzureVMCloud/sidepanel.properties | 1 + .../vmagent/AzureVMCloud/templates.jelly | 65 ++ 13 files changed, 635 insertions(+), 347 deletions(-) create mode 100644 src/main/resources/com/microsoft/azure/vmagent/AzureVMAgentTemplate/index.jelly create mode 100644 src/main/resources/com/microsoft/azure/vmagent/AzureVMAgentTemplate/index.properties create mode 100644 src/main/resources/com/microsoft/azure/vmagent/AzureVMAgentTemplate/sidepanel.jelly create mode 100644 src/main/resources/com/microsoft/azure/vmagent/AzureVMAgentTemplate/sidepanel.properties create mode 100644 src/main/resources/com/microsoft/azure/vmagent/AzureVMCloud/new.jelly create mode 100644 src/main/resources/com/microsoft/azure/vmagent/AzureVMCloud/sidepanel.jelly create mode 100644 src/main/resources/com/microsoft/azure/vmagent/AzureVMCloud/sidepanel.properties create mode 100644 src/main/resources/com/microsoft/azure/vmagent/AzureVMCloud/templates.jelly diff --git a/pom.xml b/pom.xml index 0bed254d..8c9cef14 100644 --- a/pom.xml +++ b/pom.xml @@ -45,7 +45,7 @@ 9999-SNAPSHOT jenkinsci/azure-vm-agents-plugin - 2.387.3 + 2.426.1 true 883 @@ -54,8 +54,8 @@ io.jenkins.tools.bom - bom-2.387.x - 2543.vfb_1a_5fb_9496d + bom-2.426.x + 2675.v1515e14da_7a_6 import pom diff --git a/src/main/java/com/microsoft/azure/vmagent/AzureVMAgentTemplate.java b/src/main/java/com/microsoft/azure/vmagent/AzureVMAgentTemplate.java index 4f690a8e..0c7aded8 100644 --- a/src/main/java/com/microsoft/azure/vmagent/AzureVMAgentTemplate.java +++ b/src/main/java/com/microsoft/azure/vmagent/AzureVMAgentTemplate.java @@ -54,17 +54,24 @@ import hudson.model.TaskListener; import hudson.model.labels.LabelAtom; import hudson.security.ACL; +import hudson.slaves.Cloud; import hudson.slaves.RetentionStrategy; +import hudson.util.FormApply; import hudson.util.FormValidation; import hudson.util.ListBoxModel; import jenkins.model.Jenkins; +import net.sf.json.JSONObject; import org.apache.commons.lang.StringUtils; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.DoNotUse; import org.kohsuke.accmod.restrictions.NoExternalUse; +import org.kohsuke.stapler.AncestorInPath; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.DataBoundSetter; +import org.kohsuke.stapler.HttpRedirect; +import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.QueryParameter; +import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.verb.POST; import javax.servlet.ServletException; @@ -1421,6 +1428,49 @@ public List verifyTemplate() throws Exception { nsgName); } + /** + * Deletes the template. + */ + @POST + public HttpResponse doDoDelete(@AncestorInPath AzureVMCloud azureVMCloud) throws IOException { + Jenkins j = Jenkins.get(); + j.checkPermission(Jenkins.ADMINISTER); + if (azureVMCloud == null) { + throw new IllegalStateException("Cloud could not be found"); + } + azureVMCloud.removeTemplate(this); + j.save(); + // take the user back. + return new HttpRedirect("../../templates"); + } + + @POST + public HttpResponse doConfigSubmit(StaplerRequest req, @AncestorInPath AzureVMCloud azureVMCloud) + throws IOException, ServletException, Descriptor.FormException { + Jenkins j = Jenkins.get(); + j.checkPermission(Jenkins.ADMINISTER); + if (azureVMCloud == null) { + throw new IllegalStateException("Cloud could not be found"); + } + azureVMCloud.removeTemplate(this); + AzureVMAgentTemplate newTemplate = reconfigure(req, req.getSubmittedForm()); + if (StringUtils.isBlank(newTemplate.getTemplateName())) { + throw new Descriptor.FormException("Template name is mandatory", "templateName"); + } + azureVMCloud.addTemplate(newTemplate); + j.save(); + // take the user back. + return FormApply.success("../../templates"); + } + + private AzureVMAgentTemplate reconfigure(@NonNull final StaplerRequest req, JSONObject form) + throws Descriptor.FormException { + if (form == null) { + return null; + } + return getDescriptor().newInstance(req, form); + } + @Extension public static final class DescriptorImpl extends Descriptor { @@ -1440,10 +1490,12 @@ public List>> getAzureVMRetentionStrategy() { @POST public ListBoxModel doFillVirtualMachineSizeItems( - @RelativePath("..") @QueryParameter String azureCredentialsId, + @QueryParameter("cloudName") String cloudName, @QueryParameter String location) { Jenkins.get().checkPermission(Jenkins.SYSTEM_READ); + String azureCredentialsId = getAzureCredentialsIdFromCloud(cloudName); + ListBoxModel model = new ListBoxModel(); if (StringUtils.isBlank(azureCredentialsId)) { return model; @@ -1476,10 +1528,34 @@ public ListBoxModel doFillOsTypeItems() throws IOException, ServletException { return model; } + private String getAzureCredentialsIdFromCloud(String cloudName) { + AzureVMCloud cloud = getAzureCloud(cloudName); + + if (cloud != null) { + return cloud.getAzureCredentialsId(); + } + + return null; + } + + private AzureVMCloud getAzureCloud(String cloudName) { + Cloud cloud = Jenkins.get().getCloud(cloudName); + + if (cloud instanceof AzureVMCloud) { + return (AzureVMCloud) cloud; + } + + return null; + } + @POST - public ListBoxModel doFillLocationItems(@RelativePath("..") @QueryParameter String azureCredentialsId) { + public ListBoxModel doFillLocationItems( + @QueryParameter("cloudName") String cloudName + ) { Jenkins.get().checkPermission(Jenkins.SYSTEM_READ); + String azureCredentialsId = getAzureCredentialsIdFromCloud(cloudName); + ListBoxModel model = new ListBoxModel(); if (StringUtils.isBlank(azureCredentialsId)) { return model; @@ -1511,21 +1587,27 @@ public AzureComputerLauncher getDefaultComputerLauncher() { @POST public ListBoxModel doFillAvailabilitySetItems( - @RelativePath("../..") @QueryParameter String azureCredentialsId, - @RelativePath("../..") @QueryParameter String resourceGroupReferenceType, - @RelativePath("../..") @QueryParameter String newResourceGroupName, - @RelativePath("../..") @QueryParameter String existingResourceGroupName, + @QueryParameter("cloudName") String cloudName, @RelativePath("..") @QueryParameter String location) { Jenkins.get().checkPermission(Jenkins.SYSTEM_READ); ListBoxModel model = new ListBoxModel(); model.add("--- Select Availability Set in current resource group and location ---", ""); + + AzureVMCloud cloud = getAzureCloud(cloudName); + if (cloud == null) { + return model; + } + + String azureCredentialsId = cloud.getAzureCredentialsId(); if (StringUtils.isBlank(azureCredentialsId)) { return model; } - //resourceGroupReferenceType passed wrong value in 2.60.1-LTS, we won't use this value until bug resolved. - resourceGroupReferenceType = null; + String resourceGroupReferenceType = cloud.getResourceGroupReferenceType(); + String newResourceGroupName = cloud.getNewResourceGroupName(); + String existingResourceGroupName = cloud.getExistingResourceGroupName(); + try { AzureResourceManager azureClient = AzureResourceManagerCache.get(azureCredentialsId); @@ -1585,19 +1667,23 @@ public ListBoxModel doFillUsageModeItems() throws IOException, ServletException @POST public ListBoxModel doFillExistingStorageAccountNameItems( - @RelativePath("..") @QueryParameter String azureCredentialsId, - @RelativePath("..") @QueryParameter String resourceGroupReferenceType, - @RelativePath("..") @QueryParameter String newResourceGroupName, - @RelativePath("..") @QueryParameter String existingResourceGroupName, + @QueryParameter("cloudName") String cloudName, @QueryParameter String storageAccountType) { Jenkins.get().checkPermission(Jenkins.SYSTEM_READ); + AzureVMCloud cloud = getAzureCloud(cloudName); ListBoxModel model = new ListBoxModel(); + if (cloud == null) { + return model; + } + String azureCredentialsId = cloud.getAzureCredentialsId(); + if (StringUtils.isBlank(azureCredentialsId)) { return model; } - //resourceGroupReferenceType passed wrong value in 2.60.1-LTS, we won't use this value until bug resolved. - resourceGroupReferenceType = null; + String resourceGroupReferenceType = cloud.getResourceGroupReferenceType(); + String newResourceGroupName = cloud.getNewResourceGroupName(); + String existingResourceGroupName = cloud.getExistingResourceGroupName(); try { AzureResourceManager azureClient = AzureResourceManagerCache.get(azureCredentialsId); @@ -1775,12 +1861,7 @@ public FormValidation doCheckJvmOptions(@QueryParameter String value) { @POST public FormValidation doVerifyConfiguration( - @RelativePath("..") @QueryParameter String azureCredentialsId, - @RelativePath("..") @QueryParameter String resourceGroupReferenceType, - @RelativePath("..") @QueryParameter String newResourceGroupName, - @RelativePath("..") @QueryParameter String existingResourceGroupName, - @RelativePath("..") @QueryParameter String maxVirtualMachinesLimit, - @RelativePath("..") @QueryParameter String deploymentTimeout, + @QueryParameter String cloudName, @QueryParameter String templateName, @QueryParameter String labels, @QueryParameter String location, @@ -1802,7 +1883,6 @@ public FormValidation doVerifyConfiguration( @QueryParameter String galleryName, @QueryParameter String galleryImageDefinition, @QueryParameter String galleryImageVersion, - @QueryParameter boolean galleryImageSpecialized, @QueryParameter String gallerySubscriptionId, @QueryParameter String galleryResourceGroup, @RelativePath("..") @QueryParameter String sshConfig, @@ -1830,13 +1910,13 @@ public FormValidation doVerifyConfiguration( galleryResourceGroup ); - String resourceGroupName = AzureVMCloud.getResourceGroupName( - resourceGroupReferenceType, newResourceGroupName, existingResourceGroupName); + AzureVMCloud cloud = (AzureVMCloud) Jenkins.get().getCloud(cloudName); + String storageAccountName = getStorageAccountName( storageAccountNameReferenceType, newStorageAccountName, existingStorageAccountName); if (storageAccountName.trim().isEmpty()) { storageAccountName = AzureVMAgentTemplate.generateUniqueStorageAccountName( - resourceGroupName, templateName); + cloud.getResourceGroupName(), templateName); } LOGGER.log(Level.INFO, @@ -1876,7 +1956,7 @@ public FormValidation doVerifyConfiguration( "", "", "", - resourceGroupName, + cloud.getResourceGroupName(), templateName, labels, location, @@ -1909,8 +1989,8 @@ public FormValidation doVerifyConfiguration( // First validate the subscription info. If it is not correct, // then we can't validate the - String result = AzureClientHolder.getDelegate(azureCredentialsId) - .verifyConfiguration(resourceGroupName, deploymentTimeout); + String result = AzureClientHolder.getDelegate(cloud.getAzureCredentialsId()) + .verifyConfiguration(cloud.getResourceGroupName(), String.valueOf(cloud.getDeploymentTimeout())); if (!result.equals(Constants.OP_SUCCESS)) { return FormValidation.error(result); } @@ -1920,7 +2000,7 @@ public FormValidation doVerifyConfiguration( azureComputerLauncher.setSshConfig(sshConfig); } - final List errors = AzureClientHolder.getDelegate(azureCredentialsId).verifyTemplate( + final List errors = AzureClientHolder.getDelegate(cloud.getAzureCredentialsId()).verifyTemplate( templateName, labels, location, @@ -1940,7 +2020,7 @@ public FormValidation doVerifyConfiguration( subnetName, new AzureVMCloudRetensionStrategy(0), jvmOptions, - resourceGroupName, + cloud.getResourceGroupName(), false, usePrivateIP, nsgName); diff --git a/src/main/java/com/microsoft/azure/vmagent/AzureVMCloud.java b/src/main/java/com/microsoft/azure/vmagent/AzureVMCloud.java index 27ec9ff4..45c29033 100644 --- a/src/main/java/com/microsoft/azure/vmagent/AzureVMCloud.java +++ b/src/main/java/com/microsoft/azure/vmagent/AzureVMCloud.java @@ -47,10 +47,13 @@ import hudson.slaves.Cloud; import hudson.slaves.NodeProvisioner.PlannedNode; import hudson.slaves.SlaveComputer; +import hudson.util.FormApply; import hudson.util.FormValidation; import hudson.util.ListBoxModel; import hudson.util.StreamTaskListener; +import javax.servlet.ServletException; import jenkins.model.Jenkins; +import net.sf.json.JSONObject; import org.apache.commons.lang.StringUtils; import org.jenkinsci.plugins.cloudstats.CloudStatistics; import org.jenkinsci.plugins.cloudstats.ProvisioningActivity; @@ -59,7 +62,10 @@ import org.kohsuke.accmod.restrictions.NoExternalUse; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.DataBoundSetter; +import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.QueryParameter; +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.interceptor.RequirePOST; import org.kohsuke.stapler.verb.POST; @@ -321,6 +327,16 @@ public final void setVmTemplates(List newTemplates) { this.vmTemplates = new CopyOnWriteArrayList<>(newTemplates); } + public void addTemplate(AzureVMAgentTemplate template) { + template.addAzureCloudReference(this); + ensureVmTemplateList(); + vmTemplates.add(template); + } + + public void removeTemplate(AzureVMAgentTemplate t) { + this.vmTemplates.remove(t); + } + public List getCloudTags() { return cloudTags; } @@ -483,6 +499,11 @@ public AzureVMAgentTemplate getAzureAgentTemplate(Label label) { return null; } + @SuppressWarnings("unused") // called by jelly + public AzureVMAgentTemplate getTemplate(String name) { + return getAzureAgentTemplate(name); + } + /** * Returns agent template associated with the name. * @@ -490,16 +511,7 @@ public AzureVMAgentTemplate getAzureAgentTemplate(Label label) { * @return Agent template that has the name assigned */ public AzureVMAgentTemplate getAzureAgentTemplate(String name) { - if (StringUtils.isBlank(name)) { - return null; - } - - for (AzureVMAgentTemplate agentTemplate : vmTemplates) { - if (name.equals(agentTemplate.getTemplateName())) { - return agentTemplate; - } - } - return null; + return getVmTemplates().stream().filter(t -> name.equals(t.getTemplateName())).findFirst().orElse(null); } /** @@ -1036,6 +1048,36 @@ public AzureVMManagementServiceDelegate getServiceDelegate() { return AzureVMManagementServiceDelegate.getInstance(getAzureClient(), credentialsId); } + @Restricted(NoExternalUse.class) // jelly + public AzureVMAgentTemplate.DescriptorImpl getTemplateDescriptor() { + return (AzureVMAgentTemplate.DescriptorImpl) Jenkins.get().getDescriptorOrDie(AzureVMAgentTemplate.class); + } + + @POST + public HttpResponse doCreate(StaplerRequest req, StaplerResponse rsp) + throws IOException, ServletException, Descriptor.FormException { + Jenkins j = Jenkins.get(); + j.checkPermission(Jenkins.ADMINISTER); + AzureVMAgentTemplate newTemplate = getTemplateDescriptor().newInstance(req, req.getSubmittedForm()); + + if (StringUtils.isBlank(newTemplate.getTemplateName())) { + throw new Descriptor.FormException("Template name is mandatory", "templateName"); + } + + addTemplate(newTemplate); + j.save(); + // take the user back. + return FormApply.success("templates"); + } + + @Override + public Cloud reconfigure(@NonNull StaplerRequest req, JSONObject form) throws Descriptor.FormException { + // cloud configuration doesn't contain templates anymore, so just keep existing ones. + var newInstance = (AzureVMCloud) super.reconfigure(req, form); + newInstance.setVmTemplates(this.vmTemplates); + return newInstance; + } + @Extension public static class DescriptorImpl extends Descriptor { diff --git a/src/main/resources/com/microsoft/azure/vmagent/AzureVMAgentTemplate/config.jelly b/src/main/resources/com/microsoft/azure/vmagent/AzureVMAgentTemplate/config.jelly index d31fb240..464b1053 100644 --- a/src/main/resources/com/microsoft/azure/vmagent/AzureVMAgentTemplate/config.jelly +++ b/src/main/resources/com/microsoft/azure/vmagent/AzureVMAgentTemplate/config.jelly @@ -1,333 +1,334 @@ -
- + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - -
- -
-
-
- - - - - - - - - - +
- - - + + + - - - +
- - - - -
- -
-
-
-
-
+ + + + + - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + - - + + + - - - - - - - - - - - - - + + - - - + + - - - + + + - - - - - + + - - - - - - - - - + + - - - + + - - - + + - - - + + - - + + + - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -
+ + + + + + + + + + + + + + + + +
diff --git a/src/main/resources/com/microsoft/azure/vmagent/AzureVMAgentTemplate/index.jelly b/src/main/resources/com/microsoft/azure/vmagent/AzureVMAgentTemplate/index.jelly new file mode 100644 index 00000000..5893b084 --- /dev/null +++ b/src/main/resources/com/microsoft/azure/vmagent/AzureVMAgentTemplate/index.jelly @@ -0,0 +1,40 @@ + + + + + + + + +
+ + + + + ${%Delete agent template} + + + +
+ + + + + + + + + + + + + + + + +
+
+
diff --git a/src/main/resources/com/microsoft/azure/vmagent/AzureVMAgentTemplate/index.properties b/src/main/resources/com/microsoft/azure/vmagent/AzureVMAgentTemplate/index.properties new file mode 100644 index 00000000..163775fc --- /dev/null +++ b/src/main/resources/com/microsoft/azure/vmagent/AzureVMAgentTemplate/index.properties @@ -0,0 +1 @@ +delete.template=Delete the template ''{0}''? diff --git a/src/main/resources/com/microsoft/azure/vmagent/AzureVMAgentTemplate/sidepanel.jelly b/src/main/resources/com/microsoft/azure/vmagent/AzureVMAgentTemplate/sidepanel.jelly new file mode 100644 index 00000000..545db2bd --- /dev/null +++ b/src/main/resources/com/microsoft/azure/vmagent/AzureVMAgentTemplate/sidepanel.jelly @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/src/main/resources/com/microsoft/azure/vmagent/AzureVMAgentTemplate/sidepanel.properties b/src/main/resources/com/microsoft/azure/vmagent/AzureVMAgentTemplate/sidepanel.properties new file mode 100644 index 00000000..163775fc --- /dev/null +++ b/src/main/resources/com/microsoft/azure/vmagent/AzureVMAgentTemplate/sidepanel.properties @@ -0,0 +1 @@ +delete.template=Delete the template ''{0}''? diff --git a/src/main/resources/com/microsoft/azure/vmagent/AzureVMCloud/config.jelly b/src/main/resources/com/microsoft/azure/vmagent/AzureVMCloud/config.jelly index 009ef89d..fe0e7a97 100644 --- a/src/main/resources/com/microsoft/azure/vmagent/AzureVMCloud/config.jelly +++ b/src/main/resources/com/microsoft/azure/vmagent/AzureVMCloud/config.jelly @@ -56,7 +56,7 @@ with="azureCredentialsId,maxVirtualMachinesLimit,deploymentTimeout,resourceGroupReferenceType,newResourceGroupName,existingResourceGroupName"/> - - - + diff --git a/src/main/resources/com/microsoft/azure/vmagent/AzureVMCloud/new.jelly b/src/main/resources/com/microsoft/azure/vmagent/AzureVMCloud/new.jelly new file mode 100644 index 00000000..3f8bf8c5 --- /dev/null +++ b/src/main/resources/com/microsoft/azure/vmagent/AzureVMCloud/new.jelly @@ -0,0 +1,27 @@ + + + + + + + + +

${%New agent template}

+ + + + + + + + + + + + + + +
+
+ +
diff --git a/src/main/resources/com/microsoft/azure/vmagent/AzureVMCloud/sidepanel.jelly b/src/main/resources/com/microsoft/azure/vmagent/AzureVMCloud/sidepanel.jelly new file mode 100644 index 00000000..9668f300 --- /dev/null +++ b/src/main/resources/com/microsoft/azure/vmagent/AzureVMCloud/sidepanel.jelly @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/com/microsoft/azure/vmagent/AzureVMCloud/sidepanel.properties b/src/main/resources/com/microsoft/azure/vmagent/AzureVMCloud/sidepanel.properties new file mode 100644 index 00000000..4d567328 --- /dev/null +++ b/src/main/resources/com/microsoft/azure/vmagent/AzureVMCloud/sidepanel.properties @@ -0,0 +1 @@ +delete.cloud=Delete the cloud ''{0}''? diff --git a/src/main/resources/com/microsoft/azure/vmagent/AzureVMCloud/templates.jelly b/src/main/resources/com/microsoft/azure/vmagent/AzureVMCloud/templates.jelly new file mode 100644 index 00000000..1d3e21c0 --- /dev/null +++ b/src/main/resources/com/microsoft/azure/vmagent/AzureVMCloud/templates.jelly @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + ${%Add an agent template} + + + + + + + + + + + + + + + + + + +
${%Name} +
+ ${template.templateName} + +
+ + + +
+
+
+ + +
+
+
+
No agent template added yet.
+ +
+
+
+
+
+
+
+
From 4c76c0a70ea1c9d58d78ac137ec91ba4db0f7a5f Mon Sep 17 00:00:00 2001 From: Tim Jacomb Date: Mon, 8 Jan 2024 11:07:01 +0000 Subject: [PATCH 2/2] Add template name validation --- .../microsoft/azure/vmagent/AzureVMAgentTemplate.java | 5 +++++ .../java/com/microsoft/azure/vmagent/AzureVMCloud.java | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/main/java/com/microsoft/azure/vmagent/AzureVMAgentTemplate.java b/src/main/java/com/microsoft/azure/vmagent/AzureVMAgentTemplate.java index 0c7aded8..334f631f 100644 --- a/src/main/java/com/microsoft/azure/vmagent/AzureVMAgentTemplate.java +++ b/src/main/java/com/microsoft/azure/vmagent/AzureVMAgentTemplate.java @@ -1457,6 +1457,11 @@ public HttpResponse doConfigSubmit(StaplerRequest req, @AncestorInPath AzureVMCl if (StringUtils.isBlank(newTemplate.getTemplateName())) { throw new Descriptor.FormException("Template name is mandatory", "templateName"); } + boolean templateNameExists = azureCloud.templateNameExists(newTemplate.getTemplateName()); + if (templateNameExists) { + throw new Descriptor.FormException("Agent template name must be unique", "templateName"); + } + azureVMCloud.addTemplate(newTemplate); j.save(); // take the user back. diff --git a/src/main/java/com/microsoft/azure/vmagent/AzureVMCloud.java b/src/main/java/com/microsoft/azure/vmagent/AzureVMCloud.java index 45c29033..6233a83c 100644 --- a/src/main/java/com/microsoft/azure/vmagent/AzureVMCloud.java +++ b/src/main/java/com/microsoft/azure/vmagent/AzureVMCloud.java @@ -1053,6 +1053,11 @@ public AzureVMAgentTemplate.DescriptorImpl getTemplateDescriptor() { return (AzureVMAgentTemplate.DescriptorImpl) Jenkins.get().getDescriptorOrDie(AzureVMAgentTemplate.class); } + boolean templateNameExists(String templateName) { + return vmTemplates.stream() + .anyMatch(template -> templateName.equals(template.getTemplateName())); + } + @POST public HttpResponse doCreate(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException { @@ -1064,6 +1069,11 @@ public HttpResponse doCreate(StaplerRequest req, StaplerResponse rsp) throw new Descriptor.FormException("Template name is mandatory", "templateName"); } + boolean templateNameExists = templateNameExists(newTemplate.getTemplateName()); + if (templateNameExists) { + throw new Descriptor.FormException("Agent template name must be unique", "templateName"); + } + addTemplate(newTemplate); j.save(); // take the user back.