diff --git a/pom.xml b/pom.xml index f4232b0a8f..dd4f069a73 100644 --- a/pom.xml +++ b/pom.xml @@ -45,8 +45,7 @@ - - 2.401.1 + 2.415 2.401.x 2357.v1043f8578392 false diff --git a/src/main/java/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud.java b/src/main/java/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud.java index 4dd242e668..23c1a33105 100644 --- a/src/main/java/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud.java +++ b/src/main/java/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud.java @@ -19,7 +19,6 @@ import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; - import javax.servlet.ServletException; import edu.umd.cs.findbugs.annotations.CheckForNull; @@ -34,12 +33,17 @@ import org.jenkinsci.plugins.kubernetes.auth.KubernetesAuth; import org.jenkinsci.plugins.kubernetes.auth.KubernetesAuthException; import org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl; +import org.kohsuke.accmod.Restricted; +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.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; import com.cloudbees.plugins.credentials.CredentialsMatchers; import com.cloudbees.plugins.credentials.common.StandardCredentials; import com.cloudbees.plugins.credentials.common.StandardListBoxModel; @@ -58,6 +62,7 @@ import hudson.security.ACL; import hudson.slaves.Cloud; import hudson.slaves.NodeProvisioner; +import hudson.util.FormApply; import hudson.util.FormValidation; import hudson.util.ListBoxModel; import io.fabric8.kubernetes.client.KubernetesClient; @@ -600,6 +605,12 @@ public boolean canProvision(@NonNull Cloud.CloudState state) { public PodTemplate getTemplate(@CheckForNull Label label) { return PodTemplateUtils.getTemplateByLabel(label, getAllTemplates()); } + + @SuppressWarnings("unused ") // stapler + @CheckForNull + public PodTemplate getTemplate(@NonNull String id) { + return getTemplateById(id); + } @CheckForNull public PodTemplate getTemplateById(@NonNull String id) { @@ -716,6 +727,25 @@ public void setWaitForPodSec(Integer waitForPodSec) { this.waitForPodSec = waitForPodSec; } + @Restricted(NoExternalUse.class) // jelly + public PodTemplate.DescriptorImpl getTemplateDescriptor() { + return (PodTemplate.DescriptorImpl) Jenkins.get().getDescriptorOrDie(PodTemplate.class); + } + + /** + * Creating a new template. + */ + @POST + public HttpResponse doCreate(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException { + Jenkins j = Jenkins.get(); + j.checkPermission(Jenkins.ADMINISTER); + PodTemplate newTemplate = getTemplateDescriptor().newInstance(req, req.getSubmittedForm()); + addTemplate(newTemplate); + j.save(); + // take the user back. + return FormApply.success("templates"); + } + @Extension public static class DescriptorImpl extends Descriptor { @Override diff --git a/src/main/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplate.java b/src/main/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplate.java index a8e915f91f..120b0ffeb6 100644 --- a/src/main/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplate.java +++ b/src/main/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplate.java @@ -1,5 +1,6 @@ package org.csanchez.jenkins.plugins.kubernetes; +import java.io.IOException; import java.io.Serializable; import java.math.BigInteger; import java.nio.charset.StandardCharsets; @@ -15,7 +16,7 @@ import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; - +import javax.servlet.ServletException; import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; @@ -37,18 +38,24 @@ 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.StaplerRequest; +import org.kohsuke.stapler.verb.POST; import hudson.Extension; import hudson.Util; import hudson.model.labels.LabelAtom; import hudson.slaves.NodeProperty; +import hudson.util.FormApply; import hudson.util.XStream2; import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.client.KubernetesClient; import java.io.StringReader; import jenkins.model.Jenkins; +import net.sf.json.JSONObject; /** * Kubernetes Pod Template @@ -631,6 +638,44 @@ public void addEnvVars(List envVars) { } } + /** + * Deletes the template. + */ + @POST + public HttpResponse doDoDelete(@AncestorInPath KubernetesCloud kubernetesCloud) throws IOException { + Jenkins j = Jenkins.get(); + j.checkPermission(Jenkins.ADMINISTER); + if (kubernetesCloud == null) { + throw new IllegalStateException("Cloud could not be found"); + } + kubernetesCloud.removeTemplate(this); + j.save(); + // take the user back. + return new HttpRedirect("../../templates"); + } + + @POST + public HttpResponse doConfigSubmit(StaplerRequest req, @AncestorInPath KubernetesCloud kubernetesCloud) throws IOException, ServletException, Descriptor.FormException { + Jenkins j = Jenkins.get(); + j.checkPermission(Jenkins.ADMINISTER); + if (kubernetesCloud == null) { + throw new IllegalStateException("Cloud could not be found"); + } + kubernetesCloud.removeTemplate(this); + PodTemplate newTemplate = reconfigure(req, req.getSubmittedForm()); + kubernetesCloud.addTemplate(newTemplate); + j.save(); + // take the user back. + return FormApply.success("../../templates"); + } + + private PodTemplate reconfigure(@NonNull final StaplerRequest req, JSONObject form) throws Descriptor.FormException { + if (form == null) { + return null; + } + return getDescriptor().newInstance(req, form); + } + @DataBoundSetter public void setEnvVars(List envVars) { if (envVars != null) { diff --git a/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud/config.jelly b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud/config.jelly index 5567abb25e..69aaabf1d1 100644 --- a/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud/config.jelly +++ b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud/config.jelly @@ -1,3 +1,22 @@ + @@ -104,18 +123,6 @@ - - - - - - - - - - - - diff --git a/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud/new.jelly b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud/new.jelly new file mode 100644 index 0000000000..c6a4a7f022 --- /dev/null +++ b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud/new.jelly @@ -0,0 +1,44 @@ + + + + + + + + + ${%New pod template settings} + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud/sidepanel.jelly b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud/sidepanel.jelly new file mode 100644 index 0000000000..f99590aec5 --- /dev/null +++ b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud/sidepanel.jelly @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud/sidepanel.properties b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud/sidepanel.properties new file mode 100644 index 0000000000..2e7d5f3873 --- /dev/null +++ b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud/sidepanel.properties @@ -0,0 +1 @@ +delete.cloud=Delete the cloud ''{0}'' ? diff --git a/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud/templates.jelly b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud/templates.jelly new file mode 100644 index 0000000000..064cc843c6 --- /dev/null +++ b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud/templates.jelly @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + ${%Add a pod template} + + + + + + + ${%Name} + + + + + + + + ${template.name} + + + + + + + + + + + + + + + + + + + No pod template added yet. + + + + ${%Add a pod template} + + + + + + + + + + diff --git a/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/Messages.properties b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/Messages.properties index 75994e8b6b..ce43dbc89a 100644 --- a/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/Messages.properties +++ b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/Messages.properties @@ -8,4 +8,4 @@ KubernetesSlave.HomeWarning=[WARNING] HOME is set to / in the jnlp container. Yo troubles when using tools or ssh client. This usually happens if the uid doesn't have any \ entry in /etc/passwd. Please add a user to your Dockerfile or set the HOME environment \ variable to a valid directory in the pod template definition. -KubernetesCloudNotAllowed.Description=Kubernetes cloud {0} is not allowed for folder containing job {1} +KubernetesCloudNotAllowed.Description=Kubernetes cloud {0} is not allowed for folder containing job {1} \ No newline at end of file diff --git a/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/PodTemplate/config.jelly b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/PodTemplate/config.jelly index bb7c393835..86d1018374 100644 --- a/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/PodTemplate/config.jelly +++ b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/PodTemplate/config.jelly @@ -1,5 +1,21 @@ - - - - - - - - + + + + + + + - - ${it.description} - + + ${it.description} + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - - - + - - - + + + - - - + + + - - - + + + - + + + - - - + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - + + + - + - + diff --git a/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/PodTemplate/index.jelly b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/PodTemplate/index.jelly new file mode 100644 index 0000000000..d05f984ffd --- /dev/null +++ b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/PodTemplate/index.jelly @@ -0,0 +1,47 @@ + + + + + + + + + + ${%Pod template settings} + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/PodTemplate/sidepanel.jelly b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/PodTemplate/sidepanel.jelly new file mode 100644 index 0000000000..81fd388544 --- /dev/null +++ b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/PodTemplate/sidepanel.jelly @@ -0,0 +1,31 @@ + + + + + + + + + + + + diff --git a/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/PodTemplate/sidepanel.properties b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/PodTemplate/sidepanel.properties new file mode 100644 index 0000000000..71e2ae244c --- /dev/null +++ b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/PodTemplate/sidepanel.properties @@ -0,0 +1 @@ +delete.template=Delete the pod template ''{0}''? diff --git a/src/test/java/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloudTest.java b/src/test/java/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloudTest.java index 87e25c03ed..f840033990 100644 --- a/src/test/java/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloudTest.java +++ b/src/test/java/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloudTest.java @@ -20,6 +20,7 @@ import org.htmlunit.ElementNotFoundException; import org.htmlunit.html.DomElement; import org.htmlunit.html.DomNodeList; +import org.htmlunit.html.HtmlAnchor; import org.htmlunit.html.HtmlButton; import org.htmlunit.html.HtmlElement; import org.htmlunit.html.HtmlForm; @@ -69,21 +70,12 @@ public void configRoundTrip() throws Exception { j.jenkins.clouds.add(cloud); j.jenkins.save(); JenkinsRule.WebClient wc = j.createWebClient(); - HtmlPage p = getCloudPage(wc); + HtmlPage p = wc.goTo("cloud/kubernetes/configure"); HtmlForm f = p.getFormByName("config"); j.submit(f); assertEquals("PodTemplate{id='"+podTemplate.getId()+"', name='test-template', label='test'}", podTemplate.toString()); } - // TODO 2.414+ delete - private HtmlPage getCloudPage(JenkinsRule.WebClient wc) throws IOException, SAXException { - if (Jenkins.getVersion().isNewerThanOrEqualTo(new VersionNumber("2.414"))) { - return wc.goTo("cloud/kubernetes/configure"); - } else { - return wc.goTo("configureClouds/"); - } - } - @Test public void testInheritance() { @@ -269,34 +261,26 @@ public void defaultWorkspaceVolume() throws Exception { j.jenkins.clouds.add(cloud); j.jenkins.save(); JenkinsRule.WebClient wc = j.createWebClient(); - HtmlPage p = getCloudPage(wc); - HtmlForm f = p.getFormByName("config"); - HtmlButton buttonExtends = getButton(f, "Pod Templates"); - buttonExtends.click(); - HtmlButton buttonAdd = getButton(f, "Add Pod Template"); - buttonAdd.click(); - HtmlButton buttonDetails = getButton(f, "Pod Template details"); - buttonDetails.click(); - DomElement templates = p.getElementByName("templates"); - HtmlInput templateName = getInputByName(templates, "_.name"); + HtmlPage p = wc.goTo("cloud/kubernetes/new"); + HtmlForm f= p.getFormByName("config"); + HtmlInput templateName = getInputByName(f, "_.name"); templateName.setValue("default-workspace-volume"); j.submit(f); cloud = j.jenkins.clouds.get(KubernetesCloud.class); PodTemplate podTemplate = cloud.getTemplates().get(0); assertEquals("default-workspace-volume", podTemplate.getName()); assertEquals(WorkspaceVolume.getDefault(), podTemplate.getWorkspaceVolume()); - } - - // TODO 2.385+ delete - private HtmlButton getButton(HtmlForm f, String buttonText) { - HtmlButton button; - try { - button = HtmlFormUtil.getButtonByCaption(f, buttonText); - } catch (ElementNotFoundException e) { - // before https://github.com/jenkinsci/jenkins/pull/7173 the 3 dots where added by core - button = HtmlFormUtil.getButtonByCaption(f, buttonText + "..."); - } - return button; + // test whether we can edit a template + p = wc.goTo("cloud/kubernetes/template/" + podTemplate.getId() + "/"); + f= p.getFormByName("config"); + templateName = getInputByName(f, "_.name"); + templateName.setValue("default-workspace"); + j.submit(f); + podTemplate = cloud.getTemplates().get(0); + assertEquals("default-workspace", podTemplate.getName()); + p = wc.goTo("cloud/kubernetes/templates"); + DomElement row = p.getElementById("template_"+podTemplate.getId()); + assertTrue(row != null); } @Test