Skip to content

Commit f093342

Browse files
committed
Adds support for readiness probe
1 parent 2522723 commit f093342

File tree

27 files changed

+345
-1
lines changed

27 files changed

+345
-1
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,14 @@ containerTemplate(name: 'busybox', image: 'busybox', command: 'sleep', args: '99
437437
```
438438
See [Defining a liveness command](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#defining-a-liveness-command) for more details.
439439

440+
### Readiness Probe Usage
441+
```groovy
442+
containerTemplate(name: 'busybox', image: 'busybox', command: 'sleep', args: '99d',
443+
readinessProbe: containerReadinessProbe(execArgs: 'some --command', initialDelaySeconds: 30, timeoutSeconds: 1, failureThreshold: 3, periodSeconds: 10, successThreshold: 1)
444+
)
445+
```
446+
See [Define readiness probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-readiness-probes) for more details.
447+
440448
# Inheritance
441449

442450
## Overview
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package org.csanchez.jenkins.plugins.kubernetes;
2+
3+
import hudson.Extension;
4+
import hudson.model.AbstractDescribableImpl;
5+
import hudson.model.Descriptor;
6+
import org.jenkinsci.Symbol;
7+
import org.kohsuke.stapler.DataBoundConstructor;
8+
9+
import java.io.Serializable;
10+
11+
/**
12+
* Created by geanpalacios on 15/02/23.
13+
*/
14+
public class ContainerReadinessProbe extends AbstractDescribableImpl<ContainerReadinessProbe> implements Serializable {
15+
private String execArgs;
16+
private int timeoutSeconds;
17+
private int initialDelaySeconds;
18+
private int failureThreshold;
19+
private int periodSeconds;
20+
private int successThreshold;
21+
22+
@DataBoundConstructor
23+
public ContainerReadinessProbe(String execArgs, int timeoutSeconds, int initialDelaySeconds, int failureThreshold, int periodSeconds, int successThreshold) {
24+
this.execArgs = execArgs;
25+
this.timeoutSeconds = timeoutSeconds;
26+
this.initialDelaySeconds = initialDelaySeconds;
27+
this.failureThreshold = failureThreshold;
28+
this.periodSeconds = periodSeconds;
29+
this.successThreshold = successThreshold;
30+
}
31+
32+
public String getExecArgs() {
33+
return execArgs;
34+
}
35+
36+
public void setExecArgs(String execArgs) {
37+
this.execArgs = execArgs;
38+
}
39+
40+
public int getTimeoutSeconds() {
41+
return timeoutSeconds;
42+
}
43+
44+
public void setTimeoutSeconds(int timeoutSeconds) {
45+
this.timeoutSeconds = timeoutSeconds;
46+
}
47+
48+
public int getInitialDelaySeconds() {
49+
return initialDelaySeconds;
50+
}
51+
52+
public void setInitialDelaySeconds(int initialDelaySeconds) {
53+
this.initialDelaySeconds = initialDelaySeconds;
54+
}
55+
56+
public int getFailureThreshold() {
57+
return failureThreshold;
58+
}
59+
60+
public void setFailureThreshold(int failureThreshold) {
61+
this.failureThreshold = failureThreshold;
62+
}
63+
64+
public int getPeriodSeconds() {
65+
return periodSeconds;
66+
}
67+
68+
public void setPeriodSeconds(int periodSeconds) {
69+
this.periodSeconds = periodSeconds;
70+
}
71+
72+
public int getSuccessThreshold() {
73+
return successThreshold;
74+
}
75+
76+
public void setSuccessThreshold(int successThreshold) {
77+
this.successThreshold = successThreshold;
78+
}
79+
80+
@Override
81+
public String toString() {
82+
return "ContainerReadinessProbe{" +
83+
"execArgs='" + execArgs + '\'' +
84+
", timeoutSeconds=" + timeoutSeconds +
85+
", initialDelaySeconds=" + initialDelaySeconds +
86+
", failureThreshold=" + failureThreshold +
87+
", periodSeconds=" + periodSeconds +
88+
", successThreshold=" + successThreshold +
89+
'}';
90+
}
91+
92+
@Extension
93+
@Symbol("containerReadinessProbe")
94+
public static class DescriptorImpl extends Descriptor<ContainerReadinessProbe> {
95+
@Override
96+
public String getDisplayName() {
97+
return "Container Readiness Probe";
98+
}
99+
}
100+
}

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ public class ContainerTemplate extends AbstractDescribableImpl<ContainerTemplate
6969
private List<PortMapping> ports = new ArrayList<>();
7070

7171
private ContainerLivenessProbe livenessProbe;
72+
private ContainerReadinessProbe readinessProbe;
7273

7374
@Deprecated
7475
public ContainerTemplate(String image) {
@@ -111,6 +112,7 @@ public ContainerTemplate(ContainerTemplate from) {
111112
this.setEnvVars(from.getEnvVars());
112113
this.setPorts(from.getPorts());
113114
this.setLivenessProbe(from.getLivenessProbe());
115+
this.setReadinessProbe(from.getReadinessProbe());
114116
}
115117

116118
public void setName(String name) {
@@ -229,6 +231,14 @@ public void setEnvVars(List<TemplateEnvVar> envVars) {
229231
public void setLivenessProbe(ContainerLivenessProbe livenessProbe) {
230232
this.livenessProbe = livenessProbe;
231233
}
234+
235+
public ContainerReadinessProbe getReadinessProbe() { return readinessProbe; }
236+
237+
@DataBoundSetter
238+
public void setReadinessProbe(ContainerReadinessProbe readinessProbe) {
239+
this.readinessProbe = readinessProbe;
240+
}
241+
232242

233243
public List<PortMapping> getPorts() {
234244
return ports != null ? ports : Collections.emptyList();
@@ -375,6 +385,7 @@ public String toString() {
375385
(envVars == null || envVars.isEmpty() ? "" : ", envVars=" + envVars) +
376386
(ports == null || ports.isEmpty() ? "" : ", ports=" + ports) +
377387
(livenessProbe == null ? "" : ", livenessProbe=" + livenessProbe) +
388+
(readinessProbe == null ? "" : ", readinessProbe=" + readinessProbe) +
378389
'}';
379390
}
380391

@@ -446,7 +457,10 @@ public boolean equals(Object o) {
446457
if (!Objects.equals(ports, that.ports)) {
447458
return false;
448459
}
449-
return Objects.equals(livenessProbe, that.livenessProbe);
460+
if (!Objects.equals(livenessProbe, that.livenessProbe)) {
461+
return false;
462+
}
463+
return Objects.equals(readinessProbe, that.readinessProbe);
450464
}
451465

452466
@Override
@@ -471,6 +485,7 @@ public int hashCode() {
471485
result = 31 * result + (envVars != null ? envVars.hashCode() : 0);
472486
result = 31 * result + (ports != null ? ports.hashCode() : 0);
473487
result = 31 * result + (livenessProbe != null ? livenessProbe.hashCode() : 0);
488+
result = 31 * result + (readinessProbe != null ? readinessProbe.hashCode() : 0);
474489
return result;
475490
}
476491

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,19 @@ private Container createContainer(ContainerTemplate containerTemplate, Collectio
487487
.build();
488488
}
489489

490+
ContainerReadinessProbe crp = containerTemplate.getReadinessProbe();
491+
Probe readinessProbe = null;
492+
if (crp != null && parseReadinessProbe(crp.getExecArgs()) != null) {
493+
readinessProbe = new ProbeBuilder()
494+
.withExec(new ExecAction(parseReadinessProbe(crp.getExecArgs())))
495+
.withInitialDelaySeconds(crp.getInitialDelaySeconds())
496+
.withTimeoutSeconds(crp.getTimeoutSeconds())
497+
.withFailureThreshold(crp.getFailureThreshold())
498+
.withPeriodSeconds(crp.getPeriodSeconds())
499+
.withSuccessThreshold(crp.getSuccessThreshold())
500+
.build();
501+
}
502+
490503
ContainerBuilder containerBuilder = new ContainerBuilder()
491504
.withName(substituteEnv(containerTemplate.getName()))
492505
.withImage(substituteEnv(containerTemplate.getImage()))
@@ -506,6 +519,7 @@ private Container createContainer(ContainerTemplate containerTemplate, Collectio
506519
.withCommand(parseDockerCommand(containerTemplate.getCommand()))
507520
.withArgs(arguments)
508521
.withLivenessProbe(livenessProbe)
522+
.withReadinessProbe(readinessProbe)
509523
.withTty(containerTemplate.isTtyEnabled())
510524
.withNewResources()
511525
.withRequests(getResourcesMap(containerTemplate.getResourceRequestMemory(), containerTemplate.getResourceRequestCpu(),containerTemplate.getResourceRequestEphemeralStorage()))
@@ -571,6 +585,26 @@ static List<String> parseLivenessProbe(String livenessProbeExec) {
571585
return commands;
572586
}
573587

588+
/**
589+
* Split a command in the parts that ReadinessProbe needs
590+
*
591+
* @param readinessProbeExec
592+
* @return
593+
*/
594+
@Restricted(NoExternalUse.class)
595+
static List<String> parseReadinessProbe(String readinessProbeExec) {
596+
if (StringUtils.isBlank(readinessProbeExec)) {
597+
return null;
598+
}
599+
// handle quoted arguments
600+
Matcher m = SPLIT_IN_SPACES.matcher(readinessProbeExec);
601+
List<String> commands = new ArrayList<String>();
602+
while (m.find()) {
603+
commands.add(substituteEnv(m.group(1).replace("\"", "").replace("?:\\\"", "")));
604+
}
605+
return commands;
606+
}
607+
574608
private Map<String, Quantity> getResourcesMap(String memory, String cpu, String ephemeralStorage) {
575609
Map<String, Quantity> builder = new HashMap<>();
576610
String actualMemory = substituteEnv(memory);

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ public static ContainerTemplate combine(@CheckForNull ContainerTemplate parent,
109109
.collect(Collectors.toMap(PortMapping::getName, Function.identity()));
110110
template.getPorts().stream().forEach(p -> ports.put(p.getName(), p));
111111
ContainerLivenessProbe livenessProbe = template.getLivenessProbe() != null ? template.getLivenessProbe() : parent.getLivenessProbe();
112+
ContainerReadinessProbe readinessProbe = template.getReadinessProbe() != null ? template.getReadinessProbe() : parent.getReadinessProbe();
112113

113114
ContainerTemplate combined = new ContainerTemplate(image);
114115
combined.setName(name);
@@ -131,6 +132,7 @@ public static ContainerTemplate combine(@CheckForNull ContainerTemplate parent,
131132
combined.setEnvVars(combineEnvVars(parent, template));
132133
combined.setPorts(new ArrayList<>(ports.values()));
133134
combined.setLivenessProbe(livenessProbe);
135+
combined.setReadinessProbe(readinessProbe);
134136
return combined;
135137
}
136138

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<!--
2+
Config page
3+
-->
4+
<?jelly escape-by-default='true'?>
5+
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout"
6+
xmlns:t="/lib/hudson" xmlns:f="/lib/form">
7+
<f:entry field="execArgs" title="${%Exec action}">
8+
<f:textbox/>
9+
</f:entry>
10+
11+
<f:entry field="initialDelaySeconds" title="${%Initial Delay Seconds}">
12+
<f:textbox/>
13+
</f:entry>
14+
15+
<f:entry field="timeoutSeconds" title="${%Timeout Seconds}">
16+
<f:textbox/>
17+
</f:entry>
18+
19+
<f:entry field="failureThreshold" title="${%Failure Threshold}">
20+
<f:textbox/>
21+
</f:entry>
22+
23+
<f:entry field="periodSeconds" title="${%Period Seconds}">
24+
<f:textbox/>
25+
</f:entry>
26+
27+
<f:entry field="successThreshold" title="${%Success Threshold}">
28+
<f:textbox/>
29+
</f:entry>
30+
</j:jelly>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# The MIT License
2+
#
3+
# Copyright (c) 2018, Alauda
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in
13+
# all copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
# THE SOFTWARE.
22+
23+
Exec\ action=
24+
Initial\ Delay\ Seconds=
25+
Timeout\ Seconds=
26+
Failure\ Threshold=
27+
Period\ Seconds=
28+
Success\ Threshold=
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Command executed by the readiness probe.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<p>
2+
When a Pod starts and the probe fails, Kubernetes will try <em>failureThreshold</em> times before giving up.<br/>
3+
Giving up in case of liveness probe means restarting the container.<br/>
4+
In case of readiness probe the Pod will be marked Unready. Defaults to 3. Minimum value is 1.
5+
</p>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Number of seconds after the container has started before liveness or readiness probes are initiated. Defaults to 0 seconds. Minimum value is 0.

0 commit comments

Comments
 (0)