Skip to content

Commit fa556c2

Browse files
authored
Add retention strategy on pod eviction (#1712)
1 parent 37e9e7c commit fa556c2

File tree

7 files changed

+96
-2
lines changed

7 files changed

+96
-2
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ Either way it provides access to the following fields:
358358
* **annotations** Annotations to apply to the pod.
359359
* **inheritFrom** List of one or more pod templates to inherit from *(more details below)*.
360360
* **slaveConnectTimeout** Timeout in seconds for an agent to be online *(more details below)*.
361-
* **podRetention** Controls the behavior of keeping agent pods. Can be 'never()', 'onFailure()', 'always()', or 'default()' - if empty will default to deleting the pod after `activeDeadlineSeconds` has passed.
361+
* **podRetention** Controls the behavior of keeping agent pods. Can be 'never()', 'onFailure()', 'always()', 'evicted()', or 'default()' - if empty will default to deleting the pod after `activeDeadlineSeconds` has passed.
362362
* **activeDeadlineSeconds** If `podRetention` is set to `never()` or `onFailure()`, the pod is deleted after this deadline is passed.
363363
* **idleMinutes** Allows the pod to remain active for reuse until the configured number of minutes has passed since the last step was executed on it.
364364
* **showRawYaml** Enable or disable the output of the raw pod manifest. Defaults to `true`
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package org.csanchez.jenkins.plugins.kubernetes.pod.retention;
2+
3+
import hudson.Extension;
4+
import io.fabric8.kubernetes.api.model.Pod;
5+
import java.io.Serial;
6+
import java.io.Serializable;
7+
import java.util.Locale;
8+
import java.util.function.Supplier;
9+
import java.util.logging.Level;
10+
import java.util.logging.Logger;
11+
import org.csanchez.jenkins.plugins.kubernetes.KubernetesCloud;
12+
import org.jenkinsci.Symbol;
13+
import org.kohsuke.stapler.DataBoundConstructor;
14+
15+
public class Evicted extends PodRetention implements Serializable {
16+
17+
@Serial
18+
private static final long serialVersionUID = 6424267627207206819L;
19+
20+
private static final Logger LOGGER = Logger.getLogger(Evicted.class.getName());
21+
22+
@DataBoundConstructor
23+
public Evicted() {}
24+
25+
@Override
26+
public boolean shouldDeletePod(KubernetesCloud cloud, Supplier<Pod> podS) {
27+
Pod pod = null;
28+
try {
29+
pod = podS.get();
30+
} catch (RuntimeException x) {
31+
LOGGER.log(Level.WARNING, null, x);
32+
}
33+
boolean isEvicted = pod != null
34+
&& pod.getStatus() != null
35+
&& pod.getStatus().getReason() != null
36+
&& pod.getStatus().getReason().toLowerCase(Locale.getDefault()).equals("evicted");
37+
return !isEvicted;
38+
}
39+
40+
@Override
41+
public boolean equals(Object obj) {
42+
if (this == obj) {
43+
return true;
44+
}
45+
if (obj == null) {
46+
return false;
47+
}
48+
if (obj instanceof Evicted) {
49+
return true;
50+
}
51+
return false;
52+
}
53+
54+
@Override
55+
public int hashCode() {
56+
return this.toString().hashCode();
57+
}
58+
59+
@Override
60+
public String toString() {
61+
return Messages.evicted();
62+
}
63+
64+
@Extension
65+
@Symbol("evicted")
66+
public static class DescriptorImpl extends PodRetentionDescriptor {
67+
68+
@Override
69+
public String getDisplayName() {
70+
return Messages.evicted();
71+
}
72+
}
73+
}

src/main/resources/org/csanchez/jenkins/plugins/kubernetes/KubernetesCloud/help-podRetention.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<ol>
77
<li>Never - always delete the agent pod.</li>
88
<li>On Failure - keep the agent pod if it fails during the build.</li>
9+
<li>Evicted - keep the agent pod only if it was evicted during the build (For example a Node-pressure).</li>
910
<li>Always - always keep the agent pod.</li>
1011
</ol>
1112
<p>

src/main/resources/org/csanchez/jenkins/plugins/kubernetes/PodTemplate/help-podRetention.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<li>Always - always keep the agent pod.</li>
99
<li>Default - use the Pod Retention setting for the plugin.</li>
1010
<li>Never - always delete the agent pod.</li>
11+
<li>Evicted - keep the agent pod only if it was evicted during the build (For example a Node-pressure).</li>
1112
<li>On Failure - keep the agent pod if it fails during the build.</li>
1213
</ol>
1314
<p>

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ always=Always
2424
_default=Default
2525
never=Never
2626
on_Failure=On Failure
27+
evicted=Evicted
2728
PodOfflineCause.PodDeleted=Pod deleted
2829
PodOfflineCause.PodFailed=Pod failed (Reason: {0}, Message: {1})
2930
PodOfflineCause.ImagePullBackoff=Pod failed to start due to image pull failure (Reason: {0}, Image: {1})

src/test/java/org/csanchez/jenkins/plugins/kubernetes/KubernetesSlaveTest.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import java.util.Optional;
4141
import org.csanchez.jenkins.plugins.kubernetes.pod.retention.Always;
4242
import org.csanchez.jenkins.plugins.kubernetes.pod.retention.Default;
43+
import org.csanchez.jenkins.plugins.kubernetes.pod.retention.Evicted;
4344
import org.csanchez.jenkins.plugins.kubernetes.pod.retention.Never;
4445
import org.csanchez.jenkins.plugins.kubernetes.pod.retention.OnFailure;
4546
import org.csanchez.jenkins.plugins.kubernetes.pod.retention.PodRetention;
@@ -178,7 +179,11 @@ public void testGetPodRetention() {
178179
createPodRetentionTestCase(new Always(), new Default(), new Default()),
179180
createPodRetentionTestCase(new Always(), new Always(), new Always()),
180181
createPodRetentionTestCase(new Always(), new OnFailure(), new OnFailure()),
181-
createPodRetentionTestCase(new Always(), new Never(), new Never()));
182+
createPodRetentionTestCase(new Always(), new Never(), new Never()),
183+
createPodRetentionTestCase(new Evicted(), new Default(), new Default()),
184+
createPodRetentionTestCase(new Evicted(), new Always(), new Always()),
185+
createPodRetentionTestCase(new Evicted(), new OnFailure(), new OnFailure()),
186+
createPodRetentionTestCase(new Evicted(), new Never(), new Never()));
182187
KubernetesCloud cloud = new KubernetesCloud("test");
183188
r.jenkins.clouds.add(cloud);
184189
for (KubernetesSlaveTestCase<PodRetention> testCase : cases) {

src/test/java/org/csanchez/jenkins/plugins/kubernetes/pod/retention/PodRetentionTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,20 @@ public void testOnFailurePodRetention() {
6060
assertTrue(subject.shouldDeletePod(cloud, podS));
6161
}
6262

63+
@Test
64+
public void testOnEvictedPodRetention() {
65+
PodRetention subject = new Evicted();
66+
pod.setStatus(buildStatus("Failed", "Evicted"));
67+
assertFalse(subject.shouldDeletePod(cloud, podS));
68+
pod.setStatus(buildStatus("Failed", "OOMKilled"));
69+
assertTrue(subject.shouldDeletePod(cloud, podS));
70+
}
71+
6372
private PodStatus buildStatus(String phase) {
6473
return new PodStatusBuilder().withPhase(phase).build();
6574
}
75+
76+
private PodStatus buildStatus(String phase, String reason) {
77+
return new PodStatusBuilder().withPhase(phase).withReason(reason).build();
78+
}
6679
}

0 commit comments

Comments
 (0)