From 72758dff13212b53f8a4def0a0a6f4b796426643 Mon Sep 17 00:00:00 2001 From: Jaime Tobar Date: Wed, 2 May 2018 15:56:47 -0300 Subject: [PATCH 1/4] implement job/{id}/retry/{eid} api endpoint --- .../org/rundeck/client/api/RundeckApi.java | 8 ++ .../java/org/rundeck/client/tool/Main.java | 3 +- .../rundeck/client/tool/commands/Retry.java | 132 ++++++++++++++++++ .../client/tool/options/RetryBaseOptions.java | 45 ++++++ .../tool/options/RetryExecutionOption.java | 28 ++++ .../client/tool/commands/RetrySpec.groovy | 86 ++++++++++++ 6 files changed, 301 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/rundeck/client/tool/commands/Retry.java create mode 100644 src/main/java/org/rundeck/client/tool/options/RetryBaseOptions.java create mode 100644 src/main/java/org/rundeck/client/tool/options/RetryExecutionOption.java create mode 100644 src/test/groovy/org/rundeck/client/tool/commands/RetrySpec.groovy diff --git a/src/main/java/org/rundeck/client/api/RundeckApi.java b/src/main/java/org/rundeck/client/api/RundeckApi.java index 0c66b825..d2dfa30f 100644 --- a/src/main/java/org/rundeck/client/api/RundeckApi.java +++ b/src/main/java/org/rundeck/client/api/RundeckApi.java @@ -1047,4 +1047,12 @@ Call deleteReadme( @GET("user/list") Call> listUsers(); + @Headers("Accept: application/json") + @POST("job/{id}/retry/{eid}") + Call retryJob( + @Path("id") String id, + @Path("eid") String eid, + @Body JobRun jobRun + + ); } diff --git a/src/main/java/org/rundeck/client/tool/Main.java b/src/main/java/org/rundeck/client/tool/Main.java index 9aa3ec49..ec23ec35 100644 --- a/src/main/java/org/rundeck/client/tool/Main.java +++ b/src/main/java/org/rundeck/client/tool/Main.java @@ -162,7 +162,8 @@ public static Tool tool(final Rd rd) { new Tokens(rd), new Nodes(rd), new Users(rd), - new Something() + new Something(), + new Retry(rd) ) .bannerResource("rd-banner.txt") diff --git a/src/main/java/org/rundeck/client/tool/commands/Retry.java b/src/main/java/org/rundeck/client/tool/commands/Retry.java new file mode 100644 index 00000000..2d8c5167 --- /dev/null +++ b/src/main/java/org/rundeck/client/tool/commands/Retry.java @@ -0,0 +1,132 @@ +/* + * Copyright 2017 Rundeck, Inc. (http://rundeck.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.rundeck.client.tool.commands; + +import org.rundeck.client.api.model.Execution; +import org.rundeck.client.api.model.JobFileUploadResult; +import org.rundeck.client.api.model.JobRun; +import org.rundeck.client.tool.RdApp; +import org.rundeck.client.tool.commands.jobs.Files; +import org.rundeck.client.tool.options.RetryBaseOptions; +import org.rundeck.toolbelt.Command; +import org.rundeck.toolbelt.CommandOutput; +import org.rundeck.toolbelt.InputError; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +/** + * retry subcommand + */ +@Command(description = "Run a Job based on a specific execution. Specify option arguments after -- as \"-opt value\". Upload files as \"-opt " + + "@path\" or \"-opt@ path\". If they aren't specified, the options are going to be overridden by the execution options") +public class Retry extends AppCommand { + + public static final int SEC_MS = 1000; + public static final int MIN_MS = 60 * 1000; + public static final int HOUR_MS = 60 * 60 * 1000; + public static final int DAY_MS = 24 * 60 * 60 * 1000; + public static final int WEEK_MS = 7 * 24 * 60 * 60 * 1000; + + public Retry(final RdApp client) { + super(client); + } + + @Command(isDefault = true, isSolo = true) + public boolean run(RetryBaseOptions options, CommandOutput out) throws IOException, InputError { + String jobId = Run.getJobIdFromOpts(options, out, getRdApp(), () -> projectOrEnv(options)); + String execId = options.getEid(); + if (null == jobId) { + return false; + } + Execution execution; + + JobRun request = new JobRun(); + request.setLoglevel(options.getLoglevel()); + request.setAsUser(options.getUser()); + List commandString = options.getCommandString(); + Map jobopts = new HashMap<>(); + Map fileinputs = new HashMap<>(); + String key = null; + if (null != commandString) { + boolean isfile = false; + for (String part : commandString) { + if (key == null && part.startsWith("-")) { + key = part.substring(1); + if (key.endsWith("@")) { + key = key.substring(0, key.length() - 1); + isfile = true; + } + } else if (key != null) { + String filepath = null; + if (part.charAt(0) == '@' && !isfile) { + //file input + filepath = part.substring(1); + isfile = true; + } + if (isfile) { + File file = new File(filepath != null ? filepath : part); + fileinputs.put(key, file); + } + jobopts.put(key, part); + key = null; + isfile = false; + } + } + } + if (key != null) { + throw new InputError( + String.format( + "Incorrect job options, expected: \"-%s value\", but saw only \"-%s\"", + key, + key + )); + } + if (fileinputs.size() > 0) { + for (String optionName : fileinputs.keySet()) { + File file = fileinputs.get(optionName); + if (Files.invalidInputFile(file)) { + throw new InputError("File Option -" + optionName + ": File cannot be read: " + file); + } + } + for (String optionName : fileinputs.keySet()) { + File file = fileinputs.get(optionName); + JobFileUploadResult jobFileUploadResult = Files.uploadFileForJob( + getRdApp(), + file, + jobId, + optionName + ); + String fileid = jobFileUploadResult.getFileIdForOption(optionName); + jobopts.put(optionName, fileid); + out.info(String.format("File Upload OK (%s -> %s)", file, fileid)); + } + } + + request.setOptions(jobopts); + execution = apiCall(api -> api.retryJob(jobId, execId, request)); + + String started = "started"; + out.info(String.format("Execution %s: %s%n", started, execution.toBasicString())); + + return Executions.maybeFollow(getRdApp(), options, execution.getId(), out); + } +} diff --git a/src/main/java/org/rundeck/client/tool/options/RetryBaseOptions.java b/src/main/java/org/rundeck/client/tool/options/RetryBaseOptions.java new file mode 100644 index 00000000..1a222eed --- /dev/null +++ b/src/main/java/org/rundeck/client/tool/options/RetryBaseOptions.java @@ -0,0 +1,45 @@ +/* + * Copyright 2017 Rundeck, Inc. (http://rundeck.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.rundeck.client.tool.options; + +import com.lexicalscope.jewel.cli.CommandLineInterface; +import com.lexicalscope.jewel.cli.Option; +import com.lexicalscope.jewel.cli.Unparsed; +import org.rundeck.client.api.model.DateInfo; + +import java.util.List; + +@CommandLineInterface(application = "run") +public interface RetryBaseOptions extends JobIdentOptions, FollowOptions, RetryExecutionOption { + @Option(shortName = "l", + longName = "logevel", + description = "Run the command using the specified LEVEL. LEVEL can be verbose, info, warning, error.", + defaultValue = {"info"}, + pattern = "(verbose|info|warning|error)") + String getLoglevel(); + + + @Option(shortName = "u", longName = "user", description = "A username to run the job as, (runAs access required).") + String getUser(); + + boolean isUser(); + + @Unparsed(name = "-- -OPT VAL -OPT2 VAL -OPTFILE @filepath", description = "Job options") + List getCommandString(); + +} + diff --git a/src/main/java/org/rundeck/client/tool/options/RetryExecutionOption.java b/src/main/java/org/rundeck/client/tool/options/RetryExecutionOption.java new file mode 100644 index 00000000..997d1898 --- /dev/null +++ b/src/main/java/org/rundeck/client/tool/options/RetryExecutionOption.java @@ -0,0 +1,28 @@ +/* + * Copyright 2017 Rundeck, Inc. (http://rundeck.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.rundeck.client.tool.options; + +import com.lexicalscope.jewel.cli.Option; + +/** + * ID for execution + */ +public interface RetryExecutionOption { + + @Option(shortName = "e", longName = "eid", description = "Execution ID to retry on failed nodes.") + String getEid(); +} diff --git a/src/test/groovy/org/rundeck/client/tool/commands/RetrySpec.groovy b/src/test/groovy/org/rundeck/client/tool/commands/RetrySpec.groovy new file mode 100644 index 00000000..3729964c --- /dev/null +++ b/src/test/groovy/org/rundeck/client/tool/commands/RetrySpec.groovy @@ -0,0 +1,86 @@ +/* + * Copyright 2017 Rundeck, Inc. (http://rundeck.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.rundeck.client.tool.commands + +import org.rundeck.client.api.RundeckApi +import org.rundeck.client.api.model.Execution +import org.rundeck.client.api.model.JobFileUploadResult +import org.rundeck.client.api.model.JobItem +import org.rundeck.client.api.model.JobRun +import org.rundeck.client.tool.AppConfig +import org.rundeck.client.tool.RdApp +import org.rundeck.client.tool.options.RetryBaseOptions +import org.rundeck.client.tool.options.RunBaseOptions +import org.rundeck.client.util.Client +import org.rundeck.toolbelt.CommandOutput +import retrofit2.Retrofit +import retrofit2.mock.Calls +import spock.lang.Specification +import spock.lang.Unroll + +/** + * @author greg + * @since 12/13/16 + */ +class RetrySpec extends Specification { + def "run argstring supports -opt @path and -opt@ path"() { + given: + def api = Mock(RundeckApi) + def testfile1 = File.createTempFile("upload1", "test") + def testfile2 = File.createTempFile("upload2", "test") + + + def opts = Mock(RetryBaseOptions) { + isId() >> true + getId() >> 'jobid1' + getEid() >> 'eid' + getCommandString() >> [ + "-opt1", + "val1", + "-opt2", + "@$testfile1.absolutePath", + "-opt3@", + testfile2.absolutePath + ].collect { it.toString() } + } + def retrofit = new Retrofit.Builder().baseUrl('http://example.com/fake/').build() + def client = new Client(api, retrofit, null, null, 19, true, null) + def appConfig = Mock(AppConfig) + def hasclient = Mock(RdApp) { + getClient() >> client + getAppConfig() >> appConfig + } + Retry retry = new Retry(hasclient) + def out = Mock(CommandOutput) + when: + def result = retry.run(opts, out) + + then: + 1 * api.uploadJobOptionFile('jobid1', 'opt2', testfile1.name, _) >> Calls.response( + new JobFileUploadResult(total: 1, options: ['opt2': 'fakefileid1']) + ) + 1 * api.uploadJobOptionFile('jobid1', 'opt3', testfile2.name, _) >> Calls.response( + new JobFileUploadResult(total: 1, options: ['opt3': 'fakefileid2']) + ) + 1 * api.retryJob('jobid1', 'eid', { JobRun runarg -> + runarg.options == ['opt1': 'val1', 'opt2': 'fakefileid1', 'opt3': 'fakefileid2'] + } + ) >> Calls.response(new Execution(id: 123, description: '')) + 0 * api._(*_) + result + } +} From 3cf2757f3d7cc51fe8c0bf6884a76af3c34dbff2 Mon Sep 17 00:00:00 2001 From: Jaime Tobar Date: Thu, 3 May 2018 10:33:48 -0300 Subject: [PATCH 2/4] update javadoc --- src/main/java/org/rundeck/client/tool/commands/Retry.java | 2 +- .../org/rundeck/client/tool/options/RetryBaseOptions.java | 2 +- .../rundeck/client/tool/options/RetryExecutionOption.java | 2 +- .../org/rundeck/client/tool/commands/RetrySpec.groovy | 7 ++----- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/rundeck/client/tool/commands/Retry.java b/src/main/java/org/rundeck/client/tool/commands/Retry.java index 2d8c5167..02500844 100644 --- a/src/main/java/org/rundeck/client/tool/commands/Retry.java +++ b/src/main/java/org/rundeck/client/tool/commands/Retry.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Rundeck, Inc. (http://rundeck.com) + * Copyright 2018 Rundeck, Inc. (http://rundeck.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/main/java/org/rundeck/client/tool/options/RetryBaseOptions.java b/src/main/java/org/rundeck/client/tool/options/RetryBaseOptions.java index 1a222eed..8d7c3296 100644 --- a/src/main/java/org/rundeck/client/tool/options/RetryBaseOptions.java +++ b/src/main/java/org/rundeck/client/tool/options/RetryBaseOptions.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Rundeck, Inc. (http://rundeck.com) + * Copyright 2018 Rundeck, Inc. (http://rundeck.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/main/java/org/rundeck/client/tool/options/RetryExecutionOption.java b/src/main/java/org/rundeck/client/tool/options/RetryExecutionOption.java index 997d1898..49d56404 100644 --- a/src/main/java/org/rundeck/client/tool/options/RetryExecutionOption.java +++ b/src/main/java/org/rundeck/client/tool/options/RetryExecutionOption.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Rundeck, Inc. (http://rundeck.com) + * Copyright 2018 Rundeck, Inc. (http://rundeck.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/test/groovy/org/rundeck/client/tool/commands/RetrySpec.groovy b/src/test/groovy/org/rundeck/client/tool/commands/RetrySpec.groovy index 3729964c..f7b2706e 100644 --- a/src/test/groovy/org/rundeck/client/tool/commands/RetrySpec.groovy +++ b/src/test/groovy/org/rundeck/client/tool/commands/RetrySpec.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2017 Rundeck, Inc. (http://rundeck.com) + * Copyright 2018 Rundeck, Inc. (http://rundeck.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,10 +32,7 @@ import retrofit2.mock.Calls import spock.lang.Specification import spock.lang.Unroll -/** - * @author greg - * @since 12/13/16 - */ + class RetrySpec extends Specification { def "run argstring supports -opt @path and -opt@ path"() { given: From 5309ab5f72d2cbbc86c8931b3e538f38e6540c82 Mon Sep 17 00:00:00 2001 From: Jaime Tobar Date: Thu, 10 May 2018 12:30:22 -0300 Subject: [PATCH 3/4] filedNodes option to Retry --- .../org/rundeck/client/api/RundeckApi.java | 2 +- .../rundeck/client/api/model/ExecRetry.java | 51 +++++++++++++++++++ .../rundeck/client/tool/commands/Retry.java | 6 ++- .../client/tool/options/RetryBaseOptions.java | 8 ++- .../client/tool/commands/RetrySpec.groovy | 2 +- 5 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 src/main/java/org/rundeck/client/api/model/ExecRetry.java diff --git a/src/main/java/org/rundeck/client/api/RundeckApi.java b/src/main/java/org/rundeck/client/api/RundeckApi.java index d2dfa30f..0f00794c 100644 --- a/src/main/java/org/rundeck/client/api/RundeckApi.java +++ b/src/main/java/org/rundeck/client/api/RundeckApi.java @@ -1052,7 +1052,7 @@ Call deleteReadme( Call retryJob( @Path("id") String id, @Path("eid") String eid, - @Body JobRun jobRun + @Body ExecRetry execRetry ); } diff --git a/src/main/java/org/rundeck/client/api/model/ExecRetry.java b/src/main/java/org/rundeck/client/api/model/ExecRetry.java new file mode 100644 index 00000000..af42d870 --- /dev/null +++ b/src/main/java/org/rundeck/client/api/model/ExecRetry.java @@ -0,0 +1,51 @@ +/* + * Copyright 2018 Rundeck, Inc. (http://rundeck.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.rundeck.client.api.model; + + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; + + + +/** + * Parameters to run a job + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ExecRetry extends JobRun{ + private String failedNodes; + + public String getFailedNodes() { + return failedNodes; + } + + public void setFailedNodes(String failedNodes) { + this.failedNodes = failedNodes; + } + + @Override + public String toString() { + if (null != failedNodes) { + return "org.rundeck.client.api.model.ExecRetry{" + + "failedNodes='" + failedNodes + '\'' + + '}'; + } else { + return super.toString(); + } + } +} diff --git a/src/main/java/org/rundeck/client/tool/commands/Retry.java b/src/main/java/org/rundeck/client/tool/commands/Retry.java index 02500844..7faee780 100644 --- a/src/main/java/org/rundeck/client/tool/commands/Retry.java +++ b/src/main/java/org/rundeck/client/tool/commands/Retry.java @@ -16,6 +16,7 @@ package org.rundeck.client.tool.commands; +import org.rundeck.client.api.model.ExecRetry; import org.rundeck.client.api.model.Execution; import org.rundeck.client.api.model.JobFileUploadResult; import org.rundeck.client.api.model.JobRun; @@ -51,7 +52,7 @@ public Retry(final RdApp client) { } @Command(isDefault = true, isSolo = true) - public boolean run(RetryBaseOptions options, CommandOutput out) throws IOException, InputError { + public boolean retry(RetryBaseOptions options, CommandOutput out) throws IOException, InputError { String jobId = Run.getJobIdFromOpts(options, out, getRdApp(), () -> projectOrEnv(options)); String execId = options.getEid(); if (null == jobId) { @@ -59,9 +60,10 @@ public boolean run(RetryBaseOptions options, CommandOutput out) throws IOExcepti } Execution execution; - JobRun request = new JobRun(); + ExecRetry request = new ExecRetry(); request.setLoglevel(options.getLoglevel()); request.setAsUser(options.getUser()); + request.setFailedNodes(options.getFailedNodes()); List commandString = options.getCommandString(); Map jobopts = new HashMap<>(); Map fileinputs = new HashMap<>(); diff --git a/src/main/java/org/rundeck/client/tool/options/RetryBaseOptions.java b/src/main/java/org/rundeck/client/tool/options/RetryBaseOptions.java index 8d7c3296..67b6500e 100644 --- a/src/main/java/org/rundeck/client/tool/options/RetryBaseOptions.java +++ b/src/main/java/org/rundeck/client/tool/options/RetryBaseOptions.java @@ -23,7 +23,7 @@ import java.util.List; -@CommandLineInterface(application = "run") +@CommandLineInterface(application = "retry") public interface RetryBaseOptions extends JobIdentOptions, FollowOptions, RetryExecutionOption { @Option(shortName = "l", longName = "logevel", @@ -38,6 +38,12 @@ public interface RetryBaseOptions extends JobIdentOptions, FollowOptions, RetryE boolean isUser(); + @Option(shortName = "F", longName = "failedNodes", description = "Run only on failed nodes (default=true).", + defaultValue = {"true"}, + pattern = "(true|false)") + String getFailedNodes(); + + @Unparsed(name = "-- -OPT VAL -OPT2 VAL -OPTFILE @filepath", description = "Job options") List getCommandString(); diff --git a/src/test/groovy/org/rundeck/client/tool/commands/RetrySpec.groovy b/src/test/groovy/org/rundeck/client/tool/commands/RetrySpec.groovy index f7b2706e..8f6f2a10 100644 --- a/src/test/groovy/org/rundeck/client/tool/commands/RetrySpec.groovy +++ b/src/test/groovy/org/rundeck/client/tool/commands/RetrySpec.groovy @@ -64,7 +64,7 @@ class RetrySpec extends Specification { Retry retry = new Retry(hasclient) def out = Mock(CommandOutput) when: - def result = retry.run(opts, out) + def result = retry.retry(opts, out) then: 1 * api.uploadJobOptionFile('jobid1', 'opt2', testfile1.name, _) >> Calls.response( From a1ddd437ec9bc02f126ee8c9ca7781f39146d942 Mon Sep 17 00:00:00 2001 From: Jaime Tobar Date: Fri, 11 May 2018 09:42:32 -0300 Subject: [PATCH 4/4] require version 24 on Retry command --- .../rundeck/client/tool/commands/Retry.java | 1 + .../client/tool/commands/RetrySpec.groovy | 39 ++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/rundeck/client/tool/commands/Retry.java b/src/main/java/org/rundeck/client/tool/commands/Retry.java index 7faee780..c7136577 100644 --- a/src/main/java/org/rundeck/client/tool/commands/Retry.java +++ b/src/main/java/org/rundeck/client/tool/commands/Retry.java @@ -53,6 +53,7 @@ public Retry(final RdApp client) { @Command(isDefault = true, isSolo = true) public boolean retry(RetryBaseOptions options, CommandOutput out) throws IOException, InputError { + requireApiVersion("retry", 24); String jobId = Run.getJobIdFromOpts(options, out, getRdApp(), () -> projectOrEnv(options)); String execId = options.getEid(); if (null == jobId) { diff --git a/src/test/groovy/org/rundeck/client/tool/commands/RetrySpec.groovy b/src/test/groovy/org/rundeck/client/tool/commands/RetrySpec.groovy index 8f6f2a10..c1c20f76 100644 --- a/src/test/groovy/org/rundeck/client/tool/commands/RetrySpec.groovy +++ b/src/test/groovy/org/rundeck/client/tool/commands/RetrySpec.groovy @@ -27,6 +27,7 @@ import org.rundeck.client.tool.options.RetryBaseOptions import org.rundeck.client.tool.options.RunBaseOptions import org.rundeck.client.util.Client import org.rundeck.toolbelt.CommandOutput +import org.rundeck.toolbelt.InputError import retrofit2.Retrofit import retrofit2.mock.Calls import spock.lang.Specification @@ -55,7 +56,7 @@ class RetrySpec extends Specification { ].collect { it.toString() } } def retrofit = new Retrofit.Builder().baseUrl('http://example.com/fake/').build() - def client = new Client(api, retrofit, null, null, 19, true, null) + def client = new Client(api, retrofit, null, null, 24, true, null) def appConfig = Mock(AppConfig) def hasclient = Mock(RdApp) { getClient() >> client @@ -80,4 +81,40 @@ class RetrySpec extends Specification { 0 * api._(*_) result } + def "error on api version below 24"() { + given: + def api = Mock(RundeckApi) + def testfile1 = File.createTempFile("upload1", "test") + def testfile2 = File.createTempFile("upload2", "test") + + + def opts = Mock(RetryBaseOptions) { + isId() >> true + getId() >> 'jobid1' + getEid() >> 'eid' + getCommandString() >> [ + "-opt1", + "val1", + "-opt2", + "@$testfile1.absolutePath", + "-opt3@", + testfile2.absolutePath + ].collect { it.toString() } + } + def retrofit = new Retrofit.Builder().baseUrl('http://example.com/fake/').build() + def client = new Client(api, retrofit, null, null, 23, true, null) + def appConfig = Mock(AppConfig) + def hasclient = Mock(RdApp) { + getClient() >> client + getAppConfig() >> appConfig + } + Retry retry = new Retry(hasclient) + def out = Mock(CommandOutput) + when: + def result = retry.retry(opts, out) + + then: + 0 * api._(*_) + InputError e = thrown() + } }