From 34ad90a5ce8e07d67c992b598be7df79cef8345f Mon Sep 17 00:00:00 2001 From: Valentin Delaye Date: Thu, 21 Dec 2023 13:05:52 +0100 Subject: [PATCH] Add support for check mode --- README.md | 2 ++ .../ansible/AbstractAnsibleInvocation.java | 2 +- .../ansible/AnsiblePlaybookBuilder.java | 8 +++++++ .../ansible/AnsiblePlaybookInvocation.java | 14 +++++++++++ .../jobdsl/AnsibleJobDslExtension.java | 1 + .../jobdsl/context/AnsibleContext.java | 9 +++++++ .../ansible/workflow/AnsiblePlaybookStep.java | 11 +++++++++ .../AnsiblePlaybookBuilder/config.jelly | 4 ++++ .../help-checkMode.html | 3 +++ .../workflow/AnsiblePlaybookStep/config.jelly | 3 +++ .../plugins/ansible/PipelineTest.java | 11 +++++++++ .../ansible/jobdsl/JobDslIntegrationTest.java | 14 +++++++++++ src/test/resources/jobdsl/checkMode.groovy | 10 ++++++++ .../pipelines/minimalCheckMode.groovy | 24 +++++++++++++++++++ 14 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/org/jenkinsci/plugins/ansible/AnsiblePlaybookBuilder/help-checkMode.html create mode 100644 src/test/resources/jobdsl/checkMode.groovy create mode 100644 src/test/resources/pipelines/minimalCheckMode.groovy diff --git a/README.md b/README.md index 2e20170..fe2947a 100644 --- a/README.md +++ b/README.md @@ -430,6 +430,7 @@ steps { skippedTags(String tags) startAtTask(String task) credentialsId(String id) + checkMode(boolean checkMode = false) become(boolean become = true) becomeUser(String user = 'root') sudo(boolean sudo = true) @@ -477,6 +478,7 @@ steps { credentialsId('credsid') become(true) becomeUser("user") + checkMode(false) extraVars { extraVar("key1", "value1", false) extraVar("key2", "value2", true) diff --git a/src/main/java/org/jenkinsci/plugins/ansible/AbstractAnsibleInvocation.java b/src/main/java/org/jenkinsci/plugins/ansible/AbstractAnsibleInvocation.java index c6c1185..0e67ee6 100644 --- a/src/main/java/org/jenkinsci/plugins/ansible/AbstractAnsibleInvocation.java +++ b/src/main/java/org/jenkinsci/plugins/ansible/AbstractAnsibleInvocation.java @@ -52,7 +52,7 @@ abstract class AbstractAnsibleInvocation> protected boolean sudo; protected String sudoUser; protected StandardCredentials vaultCredentials; - protected FilePath vaultTmpPath; + protected FilePath vaultTmpPath = null; protected StandardUsernameCredentials credentials; protected List extraVars; protected String additionalParameters; diff --git a/src/main/java/org/jenkinsci/plugins/ansible/AnsiblePlaybookBuilder.java b/src/main/java/org/jenkinsci/plugins/ansible/AnsiblePlaybookBuilder.java index 297afd6..915f83f 100644 --- a/src/main/java/org/jenkinsci/plugins/ansible/AnsiblePlaybookBuilder.java +++ b/src/main/java/org/jenkinsci/plugins/ansible/AnsiblePlaybookBuilder.java @@ -74,6 +74,8 @@ public class AnsiblePlaybookBuilder extends Builder implements SimpleBuildStep { public String becomeUser = "root"; + public boolean checkMode = false; + public boolean sudo = false; public String sudoUser = "root"; @@ -196,6 +198,11 @@ public void setSudo(boolean sudo) { this.sudo = sudo; } + @DataBoundSetter + public void setCheckMode(boolean checkMode) { + this.checkMode = checkMode; + } + @DataBoundSetter public void setSudoUser(String sudoUser) { this.sudoUser = sudoUser; @@ -269,6 +276,7 @@ public void perform( invocation.setSkippedTags(skippedTags); invocation.setStartTask(startAtTask); invocation.setBecome(become, becomeUser); + invocation.setCheckMode(checkMode); invocation.setSudo(sudo, sudoUser); invocation.setForks(forks); invocation.setCredentials( diff --git a/src/main/java/org/jenkinsci/plugins/ansible/AnsiblePlaybookInvocation.java b/src/main/java/org/jenkinsci/plugins/ansible/AnsiblePlaybookInvocation.java index 10704bd..4439974 100644 --- a/src/main/java/org/jenkinsci/plugins/ansible/AnsiblePlaybookInvocation.java +++ b/src/main/java/org/jenkinsci/plugins/ansible/AnsiblePlaybookInvocation.java @@ -34,6 +34,7 @@ public class AnsiblePlaybookInvocation extends AbstractAnsibleInvocation build, BuildListener listener, EnvVars envVars) throws IOException, InterruptedException, AnsibleInvocationException { @@ -50,6 +51,11 @@ public AnsiblePlaybookInvocation setPlaybook(String playbook) { return this; } + public AnsiblePlaybookInvocation setCheckMode(boolean checkMode) { + this.checkMode = checkMode; + return this; + } + private ArgumentListBuilder appendPlaybook(ArgumentListBuilder args) { args.add(envVars.expand(playbook)); return args; @@ -95,6 +101,13 @@ private ArgumentListBuilder appendStartTask(ArgumentListBuilder args) { return args; } + protected ArgumentListBuilder appendCheckMode(ArgumentListBuilder args) { + if (checkMode) { + args.add("--check"); + } + return args; + } + @Override protected ArgumentListBuilder buildCommandLine() throws InterruptedException, AnsibleInvocationException, IOException { @@ -108,6 +121,7 @@ protected ArgumentListBuilder buildCommandLine() appendSkippedTags(args); appendStartTask(args); appendBecome(args); + appendCheckMode(args); appendSudo(args); appendForks(args); appendCredentials(args); diff --git a/src/main/java/org/jenkinsci/plugins/ansible/jobdsl/AnsibleJobDslExtension.java b/src/main/java/org/jenkinsci/plugins/ansible/jobdsl/AnsibleJobDslExtension.java index 87b8b81..abd55a8 100644 --- a/src/main/java/org/jenkinsci/plugins/ansible/jobdsl/AnsibleJobDslExtension.java +++ b/src/main/java/org/jenkinsci/plugins/ansible/jobdsl/AnsibleJobDslExtension.java @@ -58,6 +58,7 @@ public Object ansiblePlaybook(String playbook, Runnable closure) { plbook.setDisableHostKeyChecking(context.isDisableHostKeyChecking()); plbook.setBecome(context.isBecome()); plbook.setBecomeUser(context.getBecomeUser()); + plbook.setCheckMode(context.isCheckMode()); plbook.setSudo(context.isSudo()); plbook.setSudoUser(context.getSudoUser()); plbook.setUnbufferedOutput(context.isUnbufferedOutput()); diff --git a/src/main/java/org/jenkinsci/plugins/ansible/jobdsl/context/AnsibleContext.java b/src/main/java/org/jenkinsci/plugins/ansible/jobdsl/context/AnsibleContext.java index 55bbdef..b969212 100644 --- a/src/main/java/org/jenkinsci/plugins/ansible/jobdsl/context/AnsibleContext.java +++ b/src/main/java/org/jenkinsci/plugins/ansible/jobdsl/context/AnsibleContext.java @@ -28,6 +28,7 @@ public class AnsibleContext implements Context { private boolean sudo = false; private String sudoUser = "root"; private int forks = 5; + private boolean checkMode = false; private boolean unbufferedOutput = true; private boolean colorizedOutput = false; private boolean disableHostKeyChecking = false; @@ -107,6 +108,10 @@ public void becomeUser(String becomeUser) { this.becomeUser = becomeUser; } + public void checkMode(boolean checkMode) { + this.checkMode = checkMode; + } + public void sudo(boolean sudo) { this.sudo = sudo; } @@ -227,6 +232,10 @@ public boolean isColorizedOutput() { return colorizedOutput; } + public boolean isCheckMode() { + return checkMode; + } + public boolean isDisableHostKeyChecking() { return disableHostKeyChecking; } diff --git a/src/main/java/org/jenkinsci/plugins/ansible/workflow/AnsiblePlaybookStep.java b/src/main/java/org/jenkinsci/plugins/ansible/workflow/AnsiblePlaybookStep.java index 142b0a4..0cac7da 100644 --- a/src/main/java/org/jenkinsci/plugins/ansible/workflow/AnsiblePlaybookStep.java +++ b/src/main/java/org/jenkinsci/plugins/ansible/workflow/AnsiblePlaybookStep.java @@ -70,6 +70,7 @@ public class AnsiblePlaybookStep extends AbstractStepImpl { private String vaultCredentialsId; private String vaultTmpPath = null; private boolean become = false; + private boolean checkMode = false; private String becomeUser = "root"; private boolean sudo = false; private String sudoUser = "root"; @@ -133,6 +134,11 @@ public void setBecomeUser(String becomeUser) { this.becomeUser = Util.fixEmptyAndTrim(becomeUser); } + @DataBoundSetter + public void setCheckMode(boolean checkMode) { + this.checkMode = checkMode; + } + @DataBoundSetter public void setSudo(boolean sudo) { this.sudo = sudo; @@ -237,6 +243,10 @@ public String getBecomeUser() { return becomeUser; } + public boolean isCheckMode() { + return checkMode; + } + public boolean isSudo() { return sudo; } @@ -433,6 +443,7 @@ protected Void run() throws Exception { builder.setAnsibleName(step.getInstallation()); builder.setBecome(step.isBecome()); builder.setBecomeUser(step.getBecomeUser()); + builder.setCheckMode(step.isCheckMode()); builder.setSudo(step.isSudo()); builder.setSudoUser(step.getSudoUser()); builder.setCredentialsId(step.getCredentialsId(), true); diff --git a/src/main/resources/org/jenkinsci/plugins/ansible/AnsiblePlaybookBuilder/config.jelly b/src/main/resources/org/jenkinsci/plugins/ansible/AnsiblePlaybookBuilder/config.jelly index a96c075..25a1160 100644 --- a/src/main/resources/org/jenkinsci/plugins/ansible/AnsiblePlaybookBuilder/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/ansible/AnsiblePlaybookBuilder/config.jelly @@ -42,6 +42,10 @@ + + + + diff --git a/src/main/resources/org/jenkinsci/plugins/ansible/AnsiblePlaybookBuilder/help-checkMode.html b/src/main/resources/org/jenkinsci/plugins/ansible/AnsiblePlaybookBuilder/help-checkMode.html new file mode 100644 index 0000000..5e431bb --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/ansible/AnsiblePlaybookBuilder/help-checkMode.html @@ -0,0 +1,3 @@ +
+ Run ansible with check mode enabled. This will not make any changes on the remote system (--check) +
diff --git a/src/main/resources/org/jenkinsci/plugins/ansible/workflow/AnsiblePlaybookStep/config.jelly b/src/main/resources/org/jenkinsci/plugins/ansible/workflow/AnsiblePlaybookStep/config.jelly index 4a23974..95586a2 100644 --- a/src/main/resources/org/jenkinsci/plugins/ansible/workflow/AnsiblePlaybookStep/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/ansible/workflow/AnsiblePlaybookStep/config.jelly @@ -18,6 +18,9 @@ + + + diff --git a/src/test/java/org/jenkinsci/plugins/ansible/PipelineTest.java b/src/test/java/org/jenkinsci/plugins/ansible/PipelineTest.java index 5ea6836..b10e5c3 100644 --- a/src/test/java/org/jenkinsci/plugins/ansible/PipelineTest.java +++ b/src/test/java/org/jenkinsci/plugins/ansible/PipelineTest.java @@ -57,6 +57,17 @@ public void testMinimalPipeline() throws Exception { assertThat(run1.getLog(), allOf(containsString("ansible-playbook playbook.yml"))); } + @Test + public void testMinimalCheckModePipeline() throws Exception { + String pipeline = IOUtils.toString( + PipelineTest.class.getResourceAsStream("/pipelines/minimalCheckMode.groovy"), StandardCharsets.UTF_8); + WorkflowJob workflowJob = jenkins.createProject(WorkflowJob.class); + workflowJob.setDefinition(new CpsFlowDefinition(pipeline, true)); + WorkflowRun run1 = workflowJob.scheduleBuild2(0).waitForStart(); + jenkins.waitForCompletion(run1); + assertThat(run1.getLog(), allOf(containsString("ansible-playbook playbook.yml --check"))); + } + @Test public void testExtraVarsHiddenString() throws Exception { String pipeline = IOUtils.toString( diff --git a/src/test/java/org/jenkinsci/plugins/ansible/jobdsl/JobDslIntegrationTest.java b/src/test/java/org/jenkinsci/plugins/ansible/jobdsl/JobDslIntegrationTest.java index 0db20d3..5e841ff 100644 --- a/src/test/java/org/jenkinsci/plugins/ansible/jobdsl/JobDslIntegrationTest.java +++ b/src/test/java/org/jenkinsci/plugins/ansible/jobdsl/JobDslIntegrationTest.java @@ -40,6 +40,7 @@ public class JobDslIntegrationTest { public static final String ANSIBLE_DSL_GROOVY_PLAYBOOK = "jobdsl/playbook.groovy"; public static final String ANSIBLE_DSL_GROOVY_EXPANDER = "jobdsl/expander.groovy"; + public static final String ANSIBLE_DSL_GROOVY_CHECK_MODE = "jobdsl/checkMode.groovy"; public static final String ANSIBLE_DSL_GROOVY_SECURITY_630 = "jobdsl/security630.groovy"; public static final String ANSIBLE_DSL_GROOVY_PLAYBOOK_LEGACY = "jobdsl/legacyPlaybook.groovy"; public static final String ANSIBLE_DSL_GROOVY_ADHOC = "jobdsl/adhoc.groovy"; @@ -76,6 +77,7 @@ public void shouldCreateJobWithPlaybookDsl() throws Exception { assertThat("credentialsId", step.credentialsId, is("credsid")); assertThat("become", step.become, is(true)); assertThat("becomeUser", step.becomeUser, is("user")); + assertThat("checkMode", step.checkMode, is(false)); assertThat("sudo", step.sudo, is(false)); assertThat("sudoUser", step.sudoUser, is("root")); assertThat("forks", step.forks, is(6)); @@ -88,6 +90,18 @@ public void shouldCreateJobWithPlaybookDsl() throws Exception { assertThat("extraVar.hidden", step.extraVars.get(0).isHidden(), is(true)); } + @Test + @DslJobRule.WithJobDsl(ANSIBLE_DSL_GROOVY_CHECK_MODE) + public void shouldCreateJobWithCheckMode() throws Exception { + AnsiblePlaybookBuilder step = dsl.getGeneratedJob().getBuildersList().get(AnsiblePlaybookBuilder.class); + assertThat("Should add playbook builder", step, notNullValue()); + + assertThat("playbook", step.playbook, is("path/playbook.yml")); + assertThat("inventory", step.inventory, (Matcher) isA(InventoryPath.class)); + assertThat("ansibleName", step.ansibleName, is("1.9.4")); + assertThat("checkMode", step.checkMode, is(true)); + } + @Test @DslJobRule.WithJobDsl(ANSIBLE_DSL_GROOVY_EXPANDER) public void shouldCreateJobWithVarExpander() throws Exception { diff --git a/src/test/resources/jobdsl/checkMode.groovy b/src/test/resources/jobdsl/checkMode.groovy new file mode 100644 index 0000000..3960d8c --- /dev/null +++ b/src/test/resources/jobdsl/checkMode.groovy @@ -0,0 +1,10 @@ +freeStyleJob('ansible') { + steps { + ansiblePlaybook('path/playbook.yml') { + inventoryPath('hosts.ini') + ansibleName('1.9.4') + limit('retry.limit') + checkMode(true) + } + } +} diff --git a/src/test/resources/pipelines/minimalCheckMode.groovy b/src/test/resources/pipelines/minimalCheckMode.groovy new file mode 100644 index 0000000..39efc98 --- /dev/null +++ b/src/test/resources/pipelines/minimalCheckMode.groovy @@ -0,0 +1,24 @@ +pipeline { + agent { + label('test-agent') + } + stages { + stage('Create playbook') { + steps { + writeFile(encoding: 'UTF-8', file: 'playbook.yml', text: '''- hosts: localhost + connection: local + gather_facts: no + tasks: + - debug: msg=test + ''') + } + } + stage('Ansible playbook') { + steps { + warnError(message: 'ansible command not found?') { + ansiblePlaybook(playbook: 'playbook.yml', checkMode: true) + } + } + } + } +}