diff --git a/pom.xml b/pom.xml
index 5be9d2e374..cd5142c64a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -49,6 +49,7 @@
false
true
jenkinsci/${project.artifactId}-plugin
+ 2.2109.vb_27c2f52c324
@@ -119,6 +120,7 @@
org.jenkins-ci.plugins.workflow
workflow-cps
+ 2725.v7b_c717eb_12ce
true
@@ -136,13 +138,14 @@
org.jenkins-ci.plugins.workflow
workflow-durable-task-step
- 1174.v73a_9a_17edce0
+ 1217.v0a_5c299d0a_59
org.jenkins-ci.plugins.workflow
workflow-job
+ 1186.v8def1a_5f3944
test
@@ -165,6 +168,7 @@
org.jenkins-ci.plugins.workflow
workflow-cps
tests
+ 2725.v7b_c717eb_12ce
test
@@ -220,6 +224,12 @@
io.jenkins.configuration-as-code
test-harness
test
+
+
+ org.jenkins-ci.main
+ jenkins-test-harness
+
+
org.jenkins-ci.plugins
@@ -257,6 +267,37 @@
import
pom
+
+ org.jenkins-ci.plugins
+ script-security
+ 1172.v35f6a_0b_8207e
+
+
+ org.jenkinsci.plugins
+ pipeline-model-api
+ ${pipeline-model-definition-plugin.version}
+
+
+ org.jenkinsci.plugins
+ pipeline-model-definition
+ ${pipeline-model-definition-plugin.version}
+
+
+ org.jenkinsci.plugins
+ pipeline-model-definition
+ ${pipeline-model-definition-plugin.version}
+ tests
+
+
+ org.jenkinsci.plugins
+ pipeline-model-extensions
+ ${pipeline-model-definition-plugin.version}
+
+
+ org.jenkinsci.plugins
+ pipeline-stage-tags-metadata
+ ${pipeline-model-definition-plugin.version}
+
org.jenkins-ci.plugins
diff --git a/src/main/java/org/csanchez/jenkins/plugins/kubernetes/pipeline/KubernetesDeclarativeAgent.java b/src/main/java/org/csanchez/jenkins/plugins/kubernetes/pipeline/KubernetesDeclarativeAgent.java
index d3a397b359..103962e3ea 100644
--- a/src/main/java/org/csanchez/jenkins/plugins/kubernetes/pipeline/KubernetesDeclarativeAgent.java
+++ b/src/main/java/org/csanchez/jenkins/plugins/kubernetes/pipeline/KubernetesDeclarativeAgent.java
@@ -13,7 +13,6 @@
import org.csanchez.jenkins.plugins.kubernetes.pod.yaml.YamlMergeStrategy;
import org.csanchez.jenkins.plugins.kubernetes.volumes.workspace.WorkspaceVolume;
import org.jenkinsci.Symbol;
-import org.jenkinsci.plugins.pipeline.modeldefinition.agent.DeclarativeAgent;
import org.jenkinsci.plugins.pipeline.modeldefinition.agent.DeclarativeAgentDescriptor;
import org.jenkinsci.plugins.variant.OptionalExtension;
import org.kohsuke.accmod.Restricted;
@@ -30,8 +29,9 @@
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
+import org.jenkinsci.plugins.pipeline.modeldefinition.agent.RetryableDeclarativeAgent;
-public class KubernetesDeclarativeAgent extends DeclarativeAgent {
+public class KubernetesDeclarativeAgent extends RetryableDeclarativeAgent {
private static final Logger LOGGER = Logger.getLogger(KubernetesDeclarativeAgent.class.getName());
diff --git a/src/main/java/org/csanchez/jenkins/plugins/kubernetes/pipeline/SecretsMasker.java b/src/main/java/org/csanchez/jenkins/plugins/kubernetes/pipeline/SecretsMasker.java
index 60f51458fd..d65d1edbc6 100644
--- a/src/main/java/org/csanchez/jenkins/plugins/kubernetes/pipeline/SecretsMasker.java
+++ b/src/main/java/org/csanchez/jenkins/plugins/kubernetes/pipeline/SecretsMasker.java
@@ -84,7 +84,13 @@ protected Class type() {
@Override
protected TaskListenerDecorator get(DelegatedContext context) throws IOException, InterruptedException {
- KubernetesComputer c = context.get(KubernetesComputer.class);
+ KubernetesComputer c;
+ try {
+ c = context.get(KubernetesComputer.class);
+ } catch (IOException | InterruptedException x) {
+ LOGGER.log(Level.FINE, "Unable to look up KubernetesComputer", x);
+ return null;
+ }
if (c == null) {
return null;
}
diff --git a/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/pipeline/KubernetesDeclarativeAgent/config.jelly b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/pipeline/KubernetesDeclarativeAgent/config.jelly
index c023738226..78a4c0047d 100644
--- a/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/pipeline/KubernetesDeclarativeAgent/config.jelly
+++ b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/pipeline/KubernetesDeclarativeAgent/config.jelly
@@ -1,5 +1,5 @@
-
+
@@ -49,5 +49,6 @@
+
diff --git a/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/pipeline/KubernetesDeclarativeAgentScript.groovy b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/pipeline/KubernetesDeclarativeAgentScript.groovy
index 8023becaeb..fe316e2e19 100644
--- a/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/pipeline/KubernetesDeclarativeAgentScript.groovy
+++ b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/pipeline/KubernetesDeclarativeAgentScript.groovy
@@ -49,27 +49,36 @@ public class KubernetesDeclarativeAgentScript extends DeclarativeAgentScript 1) {
+ script.retry(count: describable.retries, conditions: [script.kubernetesAgent(), script.nonresumable()]) {
+ run.call()
+ }
+ } else {
+ run.call()
}
}
}
diff --git a/src/test/java/org/csanchez/jenkins/plugins/kubernetes/pipeline/KubernetesDeclarativeAgentTest.java b/src/test/java/org/csanchez/jenkins/plugins/kubernetes/pipeline/KubernetesDeclarativeAgentTest.java
index e18d27eeae..b965e225f4 100644
--- a/src/test/java/org/csanchez/jenkins/plugins/kubernetes/pipeline/KubernetesDeclarativeAgentTest.java
+++ b/src/test/java/org/csanchez/jenkins/plugins/kubernetes/pipeline/KubernetesDeclarativeAgentTest.java
@@ -33,6 +33,8 @@
import hudson.model.Result;
import jenkins.plugins.git.GitSampleRepoRule;
import jenkins.plugins.git.GitStep;
+import static org.csanchez.jenkins.plugins.kubernetes.KubernetesTestUtil.deletePods;
+import static org.csanchez.jenkins.plugins.kubernetes.KubernetesTestUtil.getLabels;
import org.csanchez.jenkins.plugins.kubernetes.pod.retention.OnFailure;
import org.jenkinsci.plugins.structs.describable.UninstantiatedDescribable;
import org.jenkinsci.plugins.workflow.actions.ArgumentsAction;
@@ -194,4 +196,18 @@ public void declarativeShowRawYamlFalse() throws Exception {
// check yaml metadata labels not logged
r.assertLogNotContains("class: KubernetesDeclarativeAgentTest", b);
}
+
+ @Issue("JENKINS-49707")
+ @Test
+ public void declarativeRetries() throws Exception {
+ assertNotNull(createJobThenScheduleRun());
+ r.waitForMessage("+ sleep", b);
+ deletePods(cloud.connect(), getLabels(this, name), false);
+ r.waitForMessage("busybox --", b);
+ r.waitForMessage("jnlp --", b);
+ r.waitForMessage("was deleted; cancelling node body", b);
+ r.waitForMessage("Retrying", b);
+ r.assertBuildStatusSuccess(r.waitForCompletion(b));
+ }
+
}
diff --git a/src/test/java/org/csanchez/jenkins/plugins/kubernetes/pipeline/RestartPipelineTest.java b/src/test/java/org/csanchez/jenkins/plugins/kubernetes/pipeline/RestartPipelineTest.java
index 3869594b52..2bc9ffa2be 100644
--- a/src/test/java/org/csanchez/jenkins/plugins/kubernetes/pipeline/RestartPipelineTest.java
+++ b/src/test/java/org/csanchez/jenkins/plugins/kubernetes/pipeline/RestartPipelineTest.java
@@ -45,9 +45,11 @@
import org.csanchez.jenkins.plugins.kubernetes.model.KeyValueEnvVar;
import org.csanchez.jenkins.plugins.kubernetes.model.SecretEnvVar;
import org.csanchez.jenkins.plugins.kubernetes.model.TemplateEnvVar;
+import org.csanchez.jenkins.plugins.kubernetes.pod.retention.Reaper;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
-import org.jenkinsci.plugins.workflow.support.steps.ExecutorStepExecution;
+import org.jenkinsci.plugins.workflow.steps.durable_task.DurableTaskStep;
+import org.jenkinsci.plugins.workflow.support.steps.ExecutorStepDynamicContext;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Rule;
@@ -245,12 +247,14 @@ public void terminatedPodAfterRestart() throws Exception {
projectName.set(b.getParent().getFullName());
r.waitForMessage("+ sleep", b);
});
+ logs.record(DurableTaskStep.class, Level.FINE).record(Reaper.class, Level.FINE).record(ExecutorStepDynamicContext.class, Level.FINE);
story.then(r -> {
WorkflowRun b = r.jenkins.getItemByFullName(projectName.get(), WorkflowJob.class).getBuildByNumber(1);
r.waitForMessage("Ready to run", b);
deletePods(cloud.connect(), getLabels(this, name), false);
- r.assertBuildStatus(Result.ABORTED, r.waitForCompletion(b));
- r.waitForMessage(new ExecutorStepExecution.RemovedNodeCause().getShortDescription(), b);
+ r.waitForMessage("Agent was removed", b);
+ r.waitForMessage("Retrying", b);
+ r.assertBuildStatusSuccess(r.waitForCompletion(b));
});
}
diff --git a/src/test/resources/org/csanchez/jenkins/plugins/kubernetes/pipeline/declarativeRetries.groovy b/src/test/resources/org/csanchez/jenkins/plugins/kubernetes/pipeline/declarativeRetries.groovy
new file mode 100644
index 0000000000..bf63cb20fc
--- /dev/null
+++ b/src/test/resources/org/csanchez/jenkins/plugins/kubernetes/pipeline/declarativeRetries.groovy
@@ -0,0 +1,26 @@
+pipeline {
+ agent {
+ kubernetes {
+ yaml '''
+spec:
+ containers:
+ - name: busybox
+ image: busybox
+ command:
+ - sleep
+ - 99d
+ terminationGracePeriodSeconds: 3
+ '''
+ defaultContainer 'busybox'
+ retries 2
+ }
+ }
+ stages {
+ stage('Run') {
+ steps {
+ sh 'echo hello world'
+ sh 'sleep 15'
+ }
+ }
+ }
+}
diff --git a/src/test/resources/org/csanchez/jenkins/plugins/kubernetes/pipeline/terminatedPodAfterRestart.groovy b/src/test/resources/org/csanchez/jenkins/plugins/kubernetes/pipeline/terminatedPodAfterRestart.groovy
index d1eca4791b..b4b5ef61ab 100644
--- a/src/test/resources/org/csanchez/jenkins/plugins/kubernetes/pipeline/terminatedPodAfterRestart.groovy
+++ b/src/test/resources/org/csanchez/jenkins/plugins/kubernetes/pipeline/terminatedPodAfterRestart.groovy
@@ -1,11 +1,20 @@
package org.csanchez.jenkins.plugins.kubernetes.pipeline
-podTemplate(label: '$NAME', containers: [
- containerTemplate(name: 'busybox', image: 'busybox', ttyEnabled: true, command: '/bin/cat'),
-]) {
- node ('$NAME') {
+podTemplate(yaml: '''
+spec:
+ containers:
+ - name: busybox
+ image: busybox
+ command:
+ - sleep
+ - 99d
+ terminationGracePeriodSeconds: 3
+''') {
+ retry(count: 2, conditions: [kubernetesAgent()]) {
+ node(POD_LABEL) {
container('busybox') {
- sh 'sleep 9999999'
+ sh 'sleep 15'
}
}
+ }
}