Skip to content

Commit 2d7cebd

Browse files
authored
Merge pull request #1443 from scherler/BEE-30772
2 parents 7620a7c + 18c219c commit 2d7cebd

File tree

14 files changed

+449
-128
lines changed

14 files changed

+449
-128
lines changed

pom.xml

+1-2
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@
4545
<connectorHost />
4646
<jenkins.host.address />
4747
<slaveAgentPort />
48-
<!-- TODO fix KubernetesCloudTest todos once past 2.414 -->
49-
<jenkins.version>2.401.1</jenkins.version>
48+
<jenkins.version>2.415</jenkins.version>
5049
<bom>2.401.x</bom>
5150
<bom.version>2357.v1043f8578392</bom.version>
5251
<no-test-jar>false</no-test-jar>

src/main/java/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud.java

+32-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import java.util.Set;
2020
import java.util.logging.Level;
2121
import java.util.logging.Logger;
22-
2322
import javax.servlet.ServletException;
2423

2524
import edu.umd.cs.findbugs.annotations.CheckForNull;
@@ -34,12 +33,17 @@
3433
import org.jenkinsci.plugins.kubernetes.auth.KubernetesAuth;
3534
import org.jenkinsci.plugins.kubernetes.auth.KubernetesAuthException;
3635
import org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl;
36+
import org.kohsuke.accmod.Restricted;
37+
import org.kohsuke.accmod.restrictions.NoExternalUse;
3738
import org.kohsuke.stapler.AncestorInPath;
3839
import org.kohsuke.stapler.DataBoundConstructor;
3940
import org.kohsuke.stapler.DataBoundSetter;
41+
import org.kohsuke.stapler.HttpResponse;
4042
import org.kohsuke.stapler.QueryParameter;
43+
import org.kohsuke.stapler.StaplerRequest;
44+
import org.kohsuke.stapler.StaplerResponse;
4145
import org.kohsuke.stapler.interceptor.RequirePOST;
42-
46+
import org.kohsuke.stapler.verb.POST;
4347
import com.cloudbees.plugins.credentials.CredentialsMatchers;
4448
import com.cloudbees.plugins.credentials.common.StandardCredentials;
4549
import com.cloudbees.plugins.credentials.common.StandardListBoxModel;
@@ -58,6 +62,7 @@
5862
import hudson.security.ACL;
5963
import hudson.slaves.Cloud;
6064
import hudson.slaves.NodeProvisioner;
65+
import hudson.util.FormApply;
6166
import hudson.util.FormValidation;
6267
import hudson.util.ListBoxModel;
6368
import io.fabric8.kubernetes.client.KubernetesClient;
@@ -600,6 +605,12 @@ public boolean canProvision(@NonNull Cloud.CloudState state) {
600605
public PodTemplate getTemplate(@CheckForNull Label label) {
601606
return PodTemplateUtils.getTemplateByLabel(label, getAllTemplates());
602607
}
608+
609+
@SuppressWarnings("unused ") // stapler
610+
@CheckForNull
611+
public PodTemplate getTemplate(@NonNull String id) {
612+
return getTemplateById(id);
613+
}
603614

604615
@CheckForNull
605616
public PodTemplate getTemplateById(@NonNull String id) {
@@ -716,6 +727,25 @@ public void setWaitForPodSec(Integer waitForPodSec) {
716727
this.waitForPodSec = waitForPodSec;
717728
}
718729

730+
@Restricted(NoExternalUse.class) // jelly
731+
public PodTemplate.DescriptorImpl getTemplateDescriptor() {
732+
return (PodTemplate.DescriptorImpl) Jenkins.get().getDescriptorOrDie(PodTemplate.class);
733+
}
734+
735+
/**
736+
* Creating a new template.
737+
*/
738+
@POST
739+
public HttpResponse doCreate(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException {
740+
Jenkins j = Jenkins.get();
741+
j.checkPermission(Jenkins.ADMINISTER);
742+
PodTemplate newTemplate = getTemplateDescriptor().newInstance(req, req.getSubmittedForm());
743+
addTemplate(newTemplate);
744+
j.save();
745+
// take the user back.
746+
return FormApply.success("templates");
747+
}
748+
719749
@Extension
720750
public static class DescriptorImpl extends Descriptor<Cloud> {
721751
@Override

src/main/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplate.java

+47-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.csanchez.jenkins.plugins.kubernetes;
22

3+
import java.io.IOException;
34
import java.io.Serializable;
45
import java.math.BigInteger;
56
import java.nio.charset.StandardCharsets;
@@ -15,7 +16,7 @@
1516
import java.util.UUID;
1617
import java.util.logging.Level;
1718
import java.util.logging.Logger;
18-
19+
import javax.servlet.ServletException;
1920
import edu.umd.cs.findbugs.annotations.CheckForNull;
2021
import edu.umd.cs.findbugs.annotations.NonNull;
2122
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -37,18 +38,24 @@
3738
import org.kohsuke.accmod.Restricted;
3839
import org.kohsuke.accmod.restrictions.DoNotUse;
3940
import org.kohsuke.accmod.restrictions.NoExternalUse;
41+
import org.kohsuke.stapler.AncestorInPath;
4042
import org.kohsuke.stapler.DataBoundConstructor;
4143
import org.kohsuke.stapler.DataBoundSetter;
42-
44+
import org.kohsuke.stapler.HttpRedirect;
45+
import org.kohsuke.stapler.HttpResponse;
46+
import org.kohsuke.stapler.StaplerRequest;
47+
import org.kohsuke.stapler.verb.POST;
4348
import hudson.Extension;
4449
import hudson.Util;
4550
import hudson.model.labels.LabelAtom;
4651
import hudson.slaves.NodeProperty;
52+
import hudson.util.FormApply;
4753
import hudson.util.XStream2;
4854
import io.fabric8.kubernetes.api.model.Pod;
4955
import io.fabric8.kubernetes.client.KubernetesClient;
5056
import java.io.StringReader;
5157
import jenkins.model.Jenkins;
58+
import net.sf.json.JSONObject;
5259

5360
/**
5461
* Kubernetes Pod Template
@@ -631,6 +638,44 @@ public void addEnvVars(List<TemplateEnvVar> envVars) {
631638
}
632639
}
633640

641+
/**
642+
* Deletes the template.
643+
*/
644+
@POST
645+
public HttpResponse doDoDelete(@AncestorInPath KubernetesCloud kubernetesCloud) throws IOException {
646+
Jenkins j = Jenkins.get();
647+
j.checkPermission(Jenkins.ADMINISTER);
648+
if (kubernetesCloud == null) {
649+
throw new IllegalStateException("Cloud could not be found");
650+
}
651+
kubernetesCloud.removeTemplate(this);
652+
j.save();
653+
// take the user back.
654+
return new HttpRedirect("../../templates");
655+
}
656+
657+
@POST
658+
public HttpResponse doConfigSubmit(StaplerRequest req, @AncestorInPath KubernetesCloud kubernetesCloud) throws IOException, ServletException, Descriptor.FormException {
659+
Jenkins j = Jenkins.get();
660+
j.checkPermission(Jenkins.ADMINISTER);
661+
if (kubernetesCloud == null) {
662+
throw new IllegalStateException("Cloud could not be found");
663+
}
664+
kubernetesCloud.removeTemplate(this);
665+
PodTemplate newTemplate = reconfigure(req, req.getSubmittedForm());
666+
kubernetesCloud.addTemplate(newTemplate);
667+
j.save();
668+
// take the user back.
669+
return FormApply.success("../../templates");
670+
}
671+
672+
private PodTemplate reconfigure(@NonNull final StaplerRequest req, JSONObject form) throws Descriptor.FormException {
673+
if (form == null) {
674+
return null;
675+
}
676+
return getDescriptor().newInstance(req, form);
677+
}
678+
634679
@DataBoundSetter
635680
public void setEnvVars(List<TemplateEnvVar> envVars) {
636681
if (envVars != null) {

src/main/resources/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud/config.jelly

+19-12
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
<!--
2+
The MIT License
3+
Copyright (c) 2023, CloudBees Inc.
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
The above copyright notice and this permission notice shall be included in
11+
all copies or substantial portions of the Software.
12+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
18+
THE SOFTWARE.
19+
-->
120
<?jelly escape-by-default='true'?>
221
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:c="/lib/credentials">
322

@@ -104,18 +123,6 @@
104123
<f:textbox default=""/>
105124
</f:entry>
106125
</f:advanced>
107-
</f:advanced>
108-
109-
<f:advanced title="${%Pod Templates}">
110-
<f:entry title="${%Pod Templates}" description="${%List of Pods to be launched as agents}">
111-
<f:repeatableProperty field="templates" add="${%Add Pod Template}" header="${%Pod Template}">
112-
<f:block>
113-
<div align="right">
114-
<f:repeatableDeleteButton value="${%Delete Pod Template}"/>
115-
</div>
116-
</f:block>
117-
</f:repeatableProperty>
118-
</f:entry>
119126
</f:advanced>
120127

121128
</j:jelly>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<!--
2+
The MIT License
3+
Copyright (c) 2023, CloudBees Inc.
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
The above copyright notice and this permission notice shall be included in
11+
all copies or substantial portions of the Software.
12+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
18+
THE SOFTWARE.
19+
-->
20+
<?jelly escape-by-default='true'?>
21+
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:l="/lib/layout" xmlns:f="/lib/form">
22+
<l:layout permission="${app.SYSTEM_READ}" title="${%New pod template}">
23+
<j:set var="readOnlyMode" value="${!app.hasPermission(app.ADMINISTER)}"/>
24+
<l:breadcrumb title="${%New pod template }"/>
25+
<st:include page="sidepanel.jelly" it="${it}"/>
26+
<l:main-panel>
27+
<h1>${%New pod template settings}</h1>
28+
<f:form method="post" action="create" name="config" class="jenkins-form">
29+
<!-- main body of the configuration -->
30+
31+
<j:set var="descriptor" value="${it.templateDescriptor}"/>
32+
<st:include class="${descriptor.clazz}" page="config.jelly"/>
33+
<l:isAdmin>
34+
<f:bottomButtonBar>
35+
<f:submit value="${%Create}"/>
36+
</f:bottomButtonBar>
37+
</l:isAdmin>
38+
</f:form>
39+
<l:isAdmin>
40+
<st:adjunct includes="lib.form.confirm"/>
41+
</l:isAdmin>
42+
</l:main-panel>
43+
</l:layout>
44+
</j:jelly>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<!--
2+
The MIT License
3+
Copyright (c) 2023, CloudBees Inc.
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
The above copyright notice and this permission notice shall be included in
11+
all copies or substantial portions of the Software.
12+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
18+
THE SOFTWARE.
19+
-->
20+
<?jelly escape-by-default='true'?>
21+
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:l="/lib/layout" xmlns:t="/lib/hudson">
22+
<l:header />
23+
<l:side-panel>
24+
<l:tasks>
25+
<l:task contextMenu="false" href="." icon="symbol-computer" title="${%Status}"/>
26+
<l:task href="templates" icon="symbol-details" title="${%Pod Templates}"/>
27+
<l:task href="configure" icon="symbol-settings"
28+
title="${app.hasPermission(app.ADMINISTER) ? '%Configure' : '%View Configuration'}"/>
29+
<l:delete permission="${app.ADMINISTER}" title="${%Delete Cloud}" message="${%delete.cloud(it.displayName)}"/>
30+
<t:actions />
31+
</l:tasks>
32+
<j:forEach var="action" items="${it.allActions}">
33+
<st:include it="${action}" page="box.jelly" optional="true"/>
34+
</j:forEach>
35+
</l:side-panel>
36+
</j:jelly>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
delete.cloud=Delete the cloud ''{0}'' ?
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<!--
2+
The MIT License
3+
Copyright (c) 2023, CloudBees Inc.
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
The above copyright notice and this permission notice shall be included in
11+
all copies or substantial portions of the Software.
12+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
18+
THE SOFTWARE.
19+
-->
20+
<?jelly escape-by-default='true'?>
21+
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout"
22+
xmlns:t="/lib/hudson" xmlns:f="/lib/form">
23+
<!-- with empty type attribute, takes full width space, works only because core doesn't provide a CSS "app-page-body-" -->
24+
<l:layout title="${it.name} - ${%Pod templates}"
25+
type="${request.hasParameter('expand') ? 'full-screen' : 'two-column'}">
26+
<st:include page="sidepanel.jelly"/>
27+
28+
<l:main-panel>
29+
<j:choose>
30+
<j:when test="${not empty it.templates}">
31+
<l:app-bar title="${it.name} - ${%Pod templates}">
32+
<l:isAdmin>
33+
<a name="newTemplate" class="jenkins-button jenkins-button--primary" href="new">
34+
<l:icon src="symbol-add"/>
35+
${%Add a pod template}
36+
</a>
37+
</l:isAdmin>
38+
</l:app-bar>
39+
<table id="templates" class="jenkins-table sortable">
40+
<thead>
41+
<tr>
42+
<th initialSortDir="down">${%Name}</th>
43+
<th class="jenkins-table__cell--tight"/>
44+
</tr>
45+
</thead>
46+
<tbody>
47+
<j:forEach var="template" items="${it.templates}">
48+
<tr id="template_${template.id}">
49+
<td>
50+
<a href="${it.getCloudUrl(request,app,cloud)}template/${template.id}" class="jenkins-table__button">${template.name}</a>
51+
</td>
52+
<td class="jenkins-table__cell--tight">
53+
<div class="jenkins-table__cell__button-wrapper">
54+
<a href="${it.getCloudUrl(request,app,cloud)}template/${template.id}" class="jenkins-table__button">
55+
<l:icon src="symbol-settings"/>
56+
</a>
57+
</div>
58+
</td>
59+
</tr>
60+
</j:forEach>
61+
</tbody>
62+
</table>
63+
</j:when>
64+
<j:otherwise>
65+
<l:app-bar title="${it.name} - ${%Pod templates}"/>
66+
<div >
67+
<section>
68+
<div>
69+
<div class="jenkins-!-padding-bottom-3">No pod template added yet.</div>
70+
<div>
71+
<a name="newTemplate" class="jenkins-button jenkins-button--primary" href="new">
72+
<l:icon src="symbol-add"/>
73+
${%Add a pod template}
74+
</a>
75+
</div>
76+
</div>
77+
</section>
78+
</div>
79+
</j:otherwise>
80+
</j:choose>
81+
</l:main-panel>
82+
</l:layout>
83+
</j:jelly>

src/main/resources/org/csanchez/jenkins/plugins/kubernetes/Messages.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ KubernetesSlave.HomeWarning=[WARNING] HOME is set to / in the jnlp container. Yo
88
troubles when using tools or ssh client. This usually happens if the uid doesn't have any \
99
entry in /etc/passwd. Please add a user to your Dockerfile or set the HOME environment \
1010
variable to a valid directory in the pod template definition.
11-
KubernetesCloudNotAllowed.Description=Kubernetes cloud {0} is not allowed for folder containing job {1}
11+
KubernetesCloudNotAllowed.Description=Kubernetes cloud {0} is not allowed for folder containing job {1}

0 commit comments

Comments
 (0)