diff --git a/src/main/java/org/rundeck/api/RundeckClient.java b/src/main/java/org/rundeck/api/RundeckClient.java index c04f933..6a64a26 100644 --- a/src/main/java/org/rundeck/api/RundeckClient.java +++ b/src/main/java/org/rundeck/api/RundeckClient.java @@ -915,11 +915,35 @@ public class RundeckClient implements Serializable { */ public RundeckExecution triggerJob(String jobId, Properties options, Properties nodeFilters) throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { + return triggerJob(jobId, options, nodeFilters, null); + } + /** + * Trigger the execution of a RunDeck job (identified by the given ID), and return immediately (without waiting the + * end of the job execution) + * + * @param jobId identifier of the job - mandatory + * @param options of the job - optional. See {@link OptionsBuilder}. + * @param nodeFilters for overriding the nodes on which the job will be executed - optional. See + * {@link NodeFiltersBuilder} + * @param asUser specify a user name to run the job as, must have 'runAs' permission + * @return a {@link RundeckExecution} instance for the newly created (and running) execution - won't be null + * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID) + * @throws RundeckApiLoginException if the login fails (in case of login-based authentication) + * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication) + * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace) + * @see #triggerJob(String) + * @see #runJob(String, Properties, Properties) + */ + public RundeckExecution triggerJob(String jobId, Properties options, Properties nodeFilters, String asUser) + throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { AssertUtil.notBlank(jobId, "jobId is mandatory to trigger a job !"); - return new ApiCall(this).get(new ApiPathBuilder("/job/", jobId, "/run").param("argString", - ParametersUtil.generateArgString(options)) - .nodeFilters(nodeFilters), - new ExecutionParser("result/executions/execution")); + ApiPathBuilder apiPath = new ApiPathBuilder("/job/", jobId, "/run").param("argString", + ParametersUtil.generateArgString(options)) + .nodeFilters(nodeFilters); + if(null!=asUser) { + apiPath.param("asUser", asUser); + } + return new ApiCall(this).get(apiPath, new ExecutionParser("result/executions/execution")); } /** @@ -1027,6 +1051,31 @@ public class RundeckClient implements Serializable { public RundeckExecution runJob(String jobId, Properties options, Properties nodeFilters, long poolingInterval, TimeUnit poolingUnit) throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { + return runJob(jobId, options, nodeFilters, null, poolingInterval, poolingUnit); + } + /** + * Run a RunDeck job (identified by the given ID), and wait until its execution is finished (or aborted) to return. + * We will poll the RunDeck server at regular interval (configured by the poolingInterval/poolingUnit couple) to + * know if the execution is finished (or aborted) or is still running. + * + * @param jobId identifier of the job - mandatory + * @param options of the job - optional. See {@link OptionsBuilder}. + * @param nodeFilters for overriding the nodes on which the job will be executed - optional. See + * {@link NodeFiltersBuilder} + * @param asUser specify a user name to run the job as, must have 'runAs' permission + * @param poolingInterval for checking the status of the execution. Must be > 0. + * @param poolingUnit unit (seconds, milli-seconds, ...) of the interval. Default to seconds. + * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null + * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID) + * @throws RundeckApiLoginException if the login fails (in case of login-based authentication) + * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication) + * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace) + * @see #triggerJob(String, Properties) + * @see #runJob(String, Properties, Properties, long, TimeUnit) + */ + public RundeckExecution runJob(String jobId, Properties options, Properties nodeFilters, String asUser, long poolingInterval, + TimeUnit poolingUnit) throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, + IllegalArgumentException { if (poolingInterval <= 0) { poolingInterval = DEFAULT_POOLING_INTERVAL; poolingUnit = DEFAULT_POOLING_UNIT; @@ -1035,7 +1084,7 @@ public class RundeckClient implements Serializable { poolingUnit = DEFAULT_POOLING_UNIT; } - RundeckExecution execution = triggerJob(jobId, options, nodeFilters); + RundeckExecution execution = triggerJob(jobId, options, nodeFilters, asUser); while (ExecutionStatus.RUNNING.equals(execution.getStatus())) { try { Thread.sleep(poolingUnit.toMillis(poolingInterval)); @@ -1110,16 +1159,42 @@ public class RundeckClient implements Serializable { public RundeckExecution triggerAdhocCommand(String project, String command, Properties nodeFilters, Integer nodeThreadcount, Boolean nodeKeepgoing) throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { + return triggerAdhocCommand(project, command, nodeFilters, nodeThreadcount, nodeKeepgoing, null); + } + /** + * Trigger the execution of an ad-hoc command, and return immediately (without waiting the end of the execution). + * The command will be dispatched to nodes, accordingly to the nodeFilters parameter. + * + * @param project name of the project - mandatory + * @param command to be executed - mandatory + * @param nodeFilters for selecting nodes on which the command will be executed. See {@link NodeFiltersBuilder} + * @param nodeThreadcount thread count to use (for parallelizing when running on multiple nodes) - optional + * @param nodeKeepgoing if true, continue executing on other nodes even if some fail - optional + * @param asUser specify a user name to run the job as, must have 'runAs' permission + * @return a {@link RundeckExecution} instance for the newly created (and running) execution - won't be null + * @throws RundeckApiException in case of error when calling the API (non-existent project with this name) + * @throws RundeckApiLoginException if the login fails (in case of login-based authentication) + * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication) + * @throws IllegalArgumentException if the project or command is blank (null, empty or whitespace) + * @see #triggerAdhocCommand(String, String) + * @see #runAdhocCommand(String, String, Properties) + */ + public RundeckExecution triggerAdhocCommand(String project, String command, Properties nodeFilters, + Integer nodeThreadcount, Boolean nodeKeepgoing, String asUser) throws RundeckApiException, RundeckApiLoginException, + RundeckApiTokenException, IllegalArgumentException { AssertUtil.notBlank(project, "project is mandatory to trigger an ad-hoc command !"); AssertUtil.notBlank(command, "command is mandatory to trigger an ad-hoc command !"); - RundeckExecution execution = new ApiCall(this).get(new ApiPathBuilder("/run/command").param("project", project) - .param("exec", command) - .param("nodeThreadcount", - nodeThreadcount) - .param("nodeKeepgoing", - nodeKeepgoing) - .nodeFilters(nodeFilters), - new ExecutionParser("result/execution")); + ApiPathBuilder apiPath = new ApiPathBuilder("/run/command").param("project", project) + .param("exec", command) + .param("nodeThreadcount", + nodeThreadcount) + .param("nodeKeepgoing", + nodeKeepgoing) + .nodeFilters(nodeFilters); + if(null!=asUser) { + apiPath.param("asUser", asUser); + } + RundeckExecution execution = new ApiCall(this).get(apiPath, new ExecutionParser("result/execution")); // the first call just returns the ID of the execution, so we need another call to get a "real" execution return getExecution(execution.getId()); } @@ -1266,6 +1341,31 @@ public class RundeckClient implements Serializable { public RundeckExecution runAdhocCommand(String project, String command, Properties nodeFilters, Integer nodeThreadcount, Boolean nodeKeepgoing, long poolingInterval, TimeUnit poolingUnit) throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { + return runAdhocCommand(project, command, nodeFilters, nodeThreadcount, nodeKeepgoing, null, poolingInterval, poolingUnit); + } + /** + * Run an ad-hoc command, and wait until its execution is finished (or aborted) to return. We will poll the RunDeck + * server at regular interval (configured by the poolingInterval/poolingUnit couple) to know if the execution is + * finished (or aborted) or is still running. The command will be dispatched to nodes, accordingly to the + * nodeFilters parameter. + * + * @param project name of the project - mandatory + * @param command to be executed - mandatory + * @param nodeFilters for selecting nodes on which the command will be executed. See {@link NodeFiltersBuilder} + * @param nodeThreadcount thread count to use (for parallelizing when running on multiple nodes) - optional + * @param nodeKeepgoing if true, continue executing on other nodes even if some fail - optional + * @param poolingInterval for checking the status of the execution. Must be > 0. + * @param poolingUnit unit (seconds, milli-seconds, ...) of the interval. Default to seconds. + * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null + * @throws RundeckApiException in case of error when calling the API (non-existent project with this name) + * @throws RundeckApiLoginException if the login fails (in case of login-based authentication) + * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication) + * @throws IllegalArgumentException if the project or command is blank (null, empty or whitespace) + * @see #triggerAdhocCommand(String, String, Properties, Integer, Boolean) + */ + public RundeckExecution runAdhocCommand(String project, String command, Properties nodeFilters, + Integer nodeThreadcount, Boolean nodeKeepgoing, String asUser, long poolingInterval, TimeUnit poolingUnit) + throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { if (poolingInterval <= 0) { poolingInterval = DEFAULT_POOLING_INTERVAL; poolingUnit = DEFAULT_POOLING_UNIT; @@ -1274,7 +1374,7 @@ public class RundeckClient implements Serializable { poolingUnit = DEFAULT_POOLING_UNIT; } - RundeckExecution execution = triggerAdhocCommand(project, command, nodeFilters, nodeThreadcount, nodeKeepgoing); + RundeckExecution execution = triggerAdhocCommand(project, command, nodeFilters, nodeThreadcount, nodeKeepgoing,asUser); while (ExecutionStatus.RUNNING.equals(execution.getStatus())) { try { Thread.sleep(poolingUnit.toMillis(poolingInterval)); @@ -1377,11 +1477,35 @@ public class RundeckClient implements Serializable { public RundeckExecution triggerAdhocScript(String project, String scriptFilename, Properties options, Properties nodeFilters, Integer nodeThreadcount, Boolean nodeKeepgoing) throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, IOException { + return triggerAdhocScript(project, scriptFilename, options, nodeFilters, nodeThreadcount, nodeKeepgoing, null); + } + /** + * Trigger the execution of an ad-hoc script, and return immediately (without waiting the end of the execution). The + * script will be dispatched to nodes, accordingly to the nodeFilters parameter. + * + * @param project name of the project - mandatory + * @param scriptFilename filename of the script to be executed - mandatory + * @param options of the script - optional. See {@link OptionsBuilder}. + * @param nodeFilters for selecting nodes on which the command will be executed. See {@link NodeFiltersBuilder} + * @param nodeThreadcount thread count to use (for parallelizing when running on multiple nodes) - optional + * @param nodeKeepgoing if true, continue executing on other nodes even if some fail - optional + * @return a {@link RundeckExecution} instance for the newly created (and running) execution - won't be null + * @throws RundeckApiException in case of error when calling the API (non-existent project with this name) + * @throws RundeckApiLoginException if the login fails (in case of login-based authentication) + * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication) + * @throws IllegalArgumentException if the project or scriptFilename is blank (null, empty or whitespace) + * @throws IOException if we failed to read the file + * @see #triggerAdhocScript(String, InputStream, Properties, Properties, Integer, Boolean) + * @see #runAdhocScript(String, String, Properties, Properties, Integer, Boolean, long, TimeUnit) + */ + public RundeckExecution triggerAdhocScript(String project, String scriptFilename, Properties options, + Properties nodeFilters, Integer nodeThreadcount, Boolean nodeKeepgoing,String asUser) throws RundeckApiException, + RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, IOException { AssertUtil.notBlank(scriptFilename, "scriptFilename is mandatory to trigger an ad-hoc script !"); FileInputStream stream = null; try { stream = FileUtils.openInputStream(new File(scriptFilename)); - return triggerAdhocScript(project, stream, options, nodeFilters, nodeThreadcount, nodeKeepgoing); + return triggerAdhocScript(project, stream, options, nodeFilters, nodeThreadcount, nodeKeepgoing, asUser); } finally { IOUtils.closeQuietly(stream); } @@ -1469,19 +1593,45 @@ public class RundeckClient implements Serializable { public RundeckExecution triggerAdhocScript(String project, InputStream script, Properties options, Properties nodeFilters, Integer nodeThreadcount, Boolean nodeKeepgoing) throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { + return triggerAdhocScript(project, script, options, nodeFilters, nodeThreadcount, nodeKeepgoing, null); + } + /** + * Trigger the execution of an ad-hoc script, and return immediately (without waiting the end of the execution). The + * script will be dispatched to nodes, accordingly to the nodeFilters parameter. + * + * @param project name of the project - mandatory + * @param script inputStream for reading the script to be executed - mandatory + * @param options of the script - optional. See {@link OptionsBuilder}. + * @param nodeFilters for selecting nodes on which the command will be executed. See {@link NodeFiltersBuilder} + * @param nodeThreadcount thread count to use (for parallelizing when running on multiple nodes) - optional + * @param nodeKeepgoing if true, continue executing on other nodes even if some fail - optional + * @return a {@link RundeckExecution} instance for the newly created (and running) execution - won't be null + * @throws RundeckApiException in case of error when calling the API (non-existent project with this name) + * @throws RundeckApiLoginException if the login fails (in case of login-based authentication) + * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication) + * @throws IllegalArgumentException if the project is blank (null, empty or whitespace) or the script is null + * @see #triggerAdhocScript(String, String, Properties, Properties, Integer, Boolean) + * @see #runAdhocScript(String, InputStream, Properties, Properties, Integer, Boolean, long, TimeUnit) + */ + public RundeckExecution triggerAdhocScript(String project, InputStream script, Properties options, + Properties nodeFilters, Integer nodeThreadcount, Boolean nodeKeepgoing, String asUser) throws RundeckApiException, + RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { AssertUtil.notBlank(project, "project is mandatory to trigger an ad-hoc script !"); AssertUtil.notNull(script, "script is mandatory to trigger an ad-hoc script !"); - RundeckExecution execution = new ApiCall(this).post(new ApiPathBuilder("/run/script").param("project", project) - .attach("scriptFile", - script) - .param("argString", - ParametersUtil.generateArgString(options)) - .param("nodeThreadcount", - nodeThreadcount) - .param("nodeKeepgoing", - nodeKeepgoing) - .nodeFilters(nodeFilters), - new ExecutionParser("result/execution")); + ApiPathBuilder apiPath = new ApiPathBuilder("/run/script").param("project", project) + .attach("scriptFile", + script) + .param("argString", + ParametersUtil.generateArgString(options)) + .param("nodeThreadcount", + nodeThreadcount) + .param("nodeKeepgoing", + nodeKeepgoing) + .nodeFilters(nodeFilters); + if(null!=asUser) { + apiPath.param("asUser", asUser); + } + RundeckExecution execution = new ApiCall(this).post(apiPath, new ExecutionParser("result/execution")); // the first call just returns the ID of the execution, so we need another call to get a "real" execution return getExecution(execution.getId()); } @@ -1915,6 +2065,35 @@ public class RundeckClient implements Serializable { Properties nodeFilters, Integer nodeThreadcount, Boolean nodeKeepgoing, long poolingInterval, TimeUnit poolingUnit) throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { + return runAdhocScript(project, script, options, nodeFilters, nodeThreadcount, nodeKeepgoing, null, poolingInterval, poolingUnit); + } + /** + * Run an ad-hoc script, and wait until its execution is finished (or aborted) to return. We will poll the RunDeck + * server at regular interval (configured by the poolingInterval/poolingUnit couple) to know if the execution is + * finished (or aborted) or is still running. The script will be dispatched to nodes, accordingly to the nodeFilters + * parameter. + * + * @param project name of the project - mandatory + * @param script inputStream for reading the script to be executed - mandatory + * @param options of the script - optional. See {@link OptionsBuilder}. + * @param nodeFilters for selecting nodes on which the script will be executed. See {@link NodeFiltersBuilder} + * @param nodeThreadcount thread count to use (for parallelizing when running on multiple nodes) - optional + * @param nodeKeepgoing if true, continue executing on other nodes even if some fail - optional + * @param poolingInterval for checking the status of the execution. Must be > 0. + * @param poolingUnit unit (seconds, milli-seconds, ...) of the interval. Default to seconds. + * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null + * @throws RundeckApiException in case of error when calling the API (non-existent project with this name) + * @throws RundeckApiLoginException if the login fails (in case of login-based authentication) + * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication) + * @throws IllegalArgumentException if the project is blank (null, empty or whitespace) or the script is null + * @throws IOException if we failed to read the file + * @see #runAdhocScript(String, String, Properties, Properties, Integer, Boolean, long, TimeUnit) + * @see #triggerAdhocScript(String, InputStream, Properties, Properties, Integer, Boolean) + */ + public RundeckExecution runAdhocScript(String project, InputStream script, Properties options, + Properties nodeFilters, Integer nodeThreadcount, Boolean nodeKeepgoing, String asUser, long poolingInterval, + TimeUnit poolingUnit) throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, + IllegalArgumentException { if (poolingInterval <= 0) { poolingInterval = DEFAULT_POOLING_INTERVAL; poolingUnit = DEFAULT_POOLING_UNIT; @@ -1928,7 +2107,7 @@ public class RundeckClient implements Serializable { options, nodeFilters, nodeThreadcount, - nodeKeepgoing); + nodeKeepgoing,asUser); while (ExecutionStatus.RUNNING.equals(execution.getStatus())) { try { Thread.sleep(poolingUnit.toMillis(poolingInterval)); @@ -2137,9 +2316,27 @@ public class RundeckClient implements Serializable { */ public RundeckAbort abortExecution(Long executionId) throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { + return abortExecution(executionId, null); + } + /** + * Abort an execution (identified by the given ID). The execution should be running... + * + * @param executionId identifier of the execution - mandatory + * @param asUser specify a user name to abort the job as, must have 'killAs' permission + * @return a {@link RundeckAbort} instance - won't be null + * @throws RundeckApiException in case of error when calling the API (non-existent execution with this ID) + * @throws RundeckApiLoginException if the login fails (in case of login-based authentication) + * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication) + * @throws IllegalArgumentException if the executionId is null + */ + public RundeckAbort abortExecution(Long executionId, final String asUser) throws RundeckApiException, RundeckApiLoginException, + RundeckApiTokenException, IllegalArgumentException { AssertUtil.notNull(executionId, "executionId is mandatory to abort an execution !"); - return new ApiCall(this).get(new ApiPathBuilder("/execution/", executionId.toString(), "/abort"), - new AbortParser("result/abort")); + ApiPathBuilder apiPath = new ApiPathBuilder("/execution/", executionId.toString(), "/abort"); + if(null!=asUser) { + apiPath.param("asUser", asUser); + } + return new ApiCall(this).get(apiPath, new AbortParser("result/abort")); } /* diff --git a/src/test/java/org/rundeck/api/RundeckClientTest.java b/src/test/java/org/rundeck/api/RundeckClientTest.java index 5fc8843..f5de6ae 100644 --- a/src/test/java/org/rundeck/api/RundeckClientTest.java +++ b/src/test/java/org/rundeck/api/RundeckClientTest.java @@ -23,15 +23,11 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.rundeck.api.domain.RundeckEvent; -import org.rundeck.api.domain.RundeckExecution; -import org.rundeck.api.domain.RundeckHistory; -import org.rundeck.api.domain.RundeckJobDelete; -import org.rundeck.api.domain.RundeckJobDeleteBulk; -import org.rundeck.api.domain.RundeckProject; +import org.rundeck.api.domain.*; import org.rundeck.api.query.ExecutionQuery; import org.rundeck.api.util.PagedResults; +import java.io.ByteArrayInputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; @@ -45,9 +41,19 @@ import java.util.List; */ public class RundeckClientTest { + /** + * Note: to add a new test, do the following: + * 1) start a rundeck server, available at hostname "rundeck.local" + * 2) login as test or admin user, and generate a token + * 3) add the test token as a new TEST_TOKEN_X, and use that in your test + * 4) run 'mvn test', and commit the new yml file generated at src/test/resources/betamax/tapes + * @see #createClient(String) + */ + public static final String TEST_TOKEN_0 = "PVnN5K3OPc5vduS3uVuVnEsD57pDC5pd"; public static final String TEST_TOKEN_1 = "0UUNkeRp4d58EDeCs7S6UdODp334DvK9"; public static final String TEST_TOKEN_2 = "PP4s4SdCRO6KUoNPd1D303Dc304ORN87"; + public static final String TEST_TOKEN_3 = "9RdEosesKP3se4oV9EKOd4s3RUeUS3ON"; @Rule public Recorder recorder = new Recorder(); @@ -323,7 +329,7 @@ public class RundeckClientTest { final RundeckJobDelete delete = deleteTest.getResults().get(0); Assert.assertFalse(delete.isSuccessful()); Assert.assertNotNull(delete.getError()); - Assert.assertEquals("notfound",delete.getErrorCode()); + Assert.assertEquals("notfound", delete.getErrorCode()); Assert.assertNull(delete.getMessage()); Assert.assertEquals("does-not-exist", delete.getId()); } @@ -345,7 +351,181 @@ public class RundeckClientTest { Assert.assertNull(delete.getMessage()); Assert.assertEquals("3a6d16be-4268-4d26-86a9-cebc1781f768", delete.getId()); } + @Test + @Betamax(tape = "trigger_job_basic") + public void triggerJobBasic() throws Exception { + RundeckClient client = createClient(TEST_TOKEN_3); + final RundeckExecution test + = client.triggerJob("3170ba0e-6093-4b58-94d2-52988aefbfc9", null, null, null); + + Assert.assertEquals((Long) 19L, test.getId()); + Assert.assertEquals(null, test.getArgstring()); + Assert.assertEquals(null, test.getAbortedBy()); + Assert.assertEquals("echo hi there ${job.username} ; sleep 90", test.getDescription()); + Assert.assertEquals("admin", test.getStartedBy()); + Assert.assertEquals(RundeckExecution.ExecutionStatus.RUNNING, test.getStatus()); + + } + @Test + @Betamax(tape = "trigger_job_as_user") + public void triggerJobAsUser() throws Exception { + RundeckClient client = createClient(TEST_TOKEN_3); + + final RundeckExecution test + = client.triggerJob("3170ba0e-6093-4b58-94d2-52988aefbfc9",null,null,"api-java-client-user-test1"); + + Assert.assertEquals((Long)20L, test.getId()); + Assert.assertEquals(null, test.getArgstring()); + Assert.assertEquals(null, test.getAbortedBy()); + Assert.assertEquals("echo hi there ${job.username} ; sleep 90", test.getDescription()); + Assert.assertEquals("api-java-client-user-test1", test.getStartedBy()); + Assert.assertEquals(RundeckExecution.ExecutionStatus.RUNNING, test.getStatus()); + + } + @Test + @Betamax(tape = "trigger_job_as_user_unauthorized") + public void triggerJobAsUserUnauthorized() throws Exception { + RundeckClient client = createClient(TEST_TOKEN_3); + + final RundeckExecution test; + try { + test = client.triggerJob("3170ba0e-6093-4b58-94d2-52988aefbfc9",null,null,"api-java-client-user-test2"); + Assert.fail("should not succeed"); + } catch (RundeckApiException e) { + Assert.assertEquals("Not authorized for action \"Run as User\" for Job ID 3170ba0e-6093-4b58-94d2-52988aefbfc9", e.getMessage()); + } + } + + @Test + @Betamax(tape = "trigger_adhoc_command") + public void triggerAdhocCommand() throws Exception { + RundeckClient client = createClient(TEST_TOKEN_3); + + final RundeckExecution test + = client.triggerAdhocCommand("test", "echo test trigger_adhoc_command"); + + Assert.assertEquals((Long) 23L, test.getId()); + Assert.assertEquals(null, test.getArgstring()); + Assert.assertEquals(null, test.getAbortedBy()); + Assert.assertEquals("echo test trigger_adhoc_command", test.getDescription()); + Assert.assertEquals("admin", test.getStartedBy()); + Assert.assertEquals(RundeckExecution.ExecutionStatus.SUCCEEDED, test.getStatus()); + } + + @Test + @Betamax(tape = "trigger_adhoc_command_as_user") + public void triggerAdhocCommandAsUser() throws Exception { + RundeckClient client = createClient(TEST_TOKEN_3); + + final RundeckExecution test + = client.triggerAdhocCommand("test", "echo test trigger_adhoc_command_as_user",null,null,null,"api-java-client-test-run-command-as-user1"); + + Assert.assertEquals((Long) 24L, test.getId()); + Assert.assertEquals(null, test.getArgstring()); + Assert.assertEquals(null, test.getAbortedBy()); + Assert.assertEquals("echo test trigger_adhoc_command_as_user", test.getDescription()); + Assert.assertEquals("api-java-client-test-run-command-as-user1", test.getStartedBy()); + Assert.assertEquals(RundeckExecution.ExecutionStatus.SUCCEEDED, test.getStatus()); + } + @Test + @Betamax(tape = "trigger_adhoc_command_as_user_unauthorized") + public void triggerAdhocCommandAsUserUnauthorized() throws Exception { + RundeckClient client = createClient(TEST_TOKEN_3); + + final RundeckExecution test; + try { + test = client.triggerAdhocCommand("test", "echo test trigger_adhoc_command_as_user",null,null,null,"api-java-client-test-run-command-as-user1"); + Assert.fail("should not succeed"); + } catch (RundeckApiException e) { + Assert.assertEquals("Not authorized for action \"Run as User\" for Run Adhoc", e.getMessage()); + } + } + + @Test + @Betamax(tape = "trigger_adhoc_script") + public void triggerAdhocScript() throws Exception { + RundeckClient client = createClient(TEST_TOKEN_3); + String script = "#!/bin/bash\n" + + "echo test trigger_adhoc_script\n"; + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(script.getBytes()); + + final RundeckExecution test + = client.triggerAdhocScript("test", byteArrayInputStream, null, null, null, null, null); + + Assert.assertEquals((Long) 25L, test.getId()); + Assert.assertEquals(null, test.getArgstring()); + Assert.assertEquals(null, test.getAbortedBy()); + Assert.assertEquals("#!/bin/bash\necho test trigger_adhoc_script", test.getDescription()); + Assert.assertEquals("admin", test.getStartedBy()); + Assert.assertEquals(RundeckExecution.ExecutionStatus.RUNNING, test.getStatus()); + } + @Test + @Betamax(tape = "trigger_adhoc_script_as_user") + public void triggerAdhocScriptAsUser() throws Exception { + RundeckClient client = createClient(TEST_TOKEN_3); + String script = "#!/bin/bash\n" + + "echo test trigger_adhoc_script\n"; + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(script.getBytes()); + + final RundeckExecution test + = client.triggerAdhocScript("test", byteArrayInputStream, null, null, null, null, "api-java-client-test-adhoc-script-as-user1"); + + Assert.assertEquals((Long) 26L, test.getId()); + Assert.assertEquals(null, test.getArgstring()); + Assert.assertEquals(null, test.getAbortedBy()); + Assert.assertEquals("#!/bin/bash\necho test trigger_adhoc_script", test.getDescription()); + Assert.assertEquals("api-java-client-test-adhoc-script-as-user1", test.getStartedBy()); + Assert.assertEquals(RundeckExecution.ExecutionStatus.RUNNING, test.getStatus()); + } + @Test + @Betamax(tape = "trigger_adhoc_script_as_user_unauthorized") + public void triggerAdhocScriptAsUserUnauthorized() throws Exception { + RundeckClient client = createClient(TEST_TOKEN_3); + String script = "#!/bin/bash\n" + + "echo test trigger_adhoc_script\n"; + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(script.getBytes()); + + try{ + final RundeckExecution test + = client.triggerAdhocScript("test", byteArrayInputStream, null, null, null, null, "api-java-client-test-adhoc-script-as-user1"); + Assert.fail("should not succeed"); + } catch (RundeckApiException e) { + Assert.assertEquals("Not authorized for action \"Run as User\" for Run Adhoc", e.getMessage()); + } + + } + @Test + @Betamax(tape = "abort_execution") + public void abortExecution() throws Exception { + RundeckClient client = createClient(TEST_TOKEN_3); + + long executionId = 21L; + final RundeckAbort test = client.abortExecution(executionId); + + Assert.assertEquals((Long) executionId,test.getExecution().getId()); + Assert.assertEquals(RundeckAbort.AbortStatus.PENDING,test.getStatus()); + } + @Test + @Betamax(tape = "abort_execution_as_user") + public void abortExecutionAsUser() throws Exception { + RundeckClient client = createClient(TEST_TOKEN_3); + + long executionId = 22L; + final RundeckAbort test = client.abortExecution(executionId,"api-java-client-test-abort-as-user1"); + + Assert.assertEquals((Long) executionId,test.getExecution().getId()); + Assert.assertEquals(RundeckAbort.AbortStatus.PENDING,test.getStatus()); + } + @Test + @Betamax(tape = "abort_execution_as_user_unauthorized") + public void abortExecutionAsUserUnauthorized() throws Exception { + RundeckClient client = createClient(TEST_TOKEN_3); + + long executionId = 28L; + final RundeckAbort test = client.abortExecution(executionId, "api-java-client-test-abort-as-user1"); + Assert.assertEquals(RundeckAbort.AbortStatus.FAILED, test.getStatus()); + } private void assertPageResults(PagedResults jobTest, final int size, final int count, final int max, final int offset, final int total) { diff --git a/src/test/resources/betamax/tapes/abort_execution.yaml b/src/test/resources/betamax/tapes/abort_execution.yaml new file mode 100644 index 0000000..a678ae1 --- /dev/null +++ b/src/test/resources/betamax/tapes/abort_execution.yaml @@ -0,0 +1,20 @@ +!tape +name: abort_execution +interactions: +- recorded: 2013-03-29T19:46:54.057Z + request: + method: GET + uri: http://rundeck.local:4440/api/5/execution/21/abort + headers: + Host: rundeck.local:4440 + Proxy-Connection: Keep-Alive + User-Agent: RunDeck API Java Client 5 + X-RunDeck-Auth-Token: 9RdEosesKP3se4oV9EKOd4s3RUeUS3ON + response: + status: 200 + headers: + Content-Type: text/xml; charset=utf-8 + Expires: Thu, 01 Jan 1970 00:00:00 GMT + Server: Jetty(6.1.21) + Set-Cookie: JSESSIONID=s0jn6bu9ijlh;Path=/ + body: 'Execution status: running' diff --git a/src/test/resources/betamax/tapes/abort_execution_as_user.yaml b/src/test/resources/betamax/tapes/abort_execution_as_user.yaml new file mode 100644 index 0000000..d3054ad --- /dev/null +++ b/src/test/resources/betamax/tapes/abort_execution_as_user.yaml @@ -0,0 +1,20 @@ +!tape +name: abort_execution_as_user +interactions: +- recorded: 2013-03-29T19:51:07.851Z + request: + method: GET + uri: http://rundeck.local:4440/api/5/execution/22/abort?asUser=api-java-client-test-abort-as-user1 + headers: + Host: rundeck.local:4440 + Proxy-Connection: Keep-Alive + User-Agent: RunDeck API Java Client 5 + X-RunDeck-Auth-Token: 9RdEosesKP3se4oV9EKOd4s3RUeUS3ON + response: + status: 200 + headers: + Content-Type: text/xml; charset=utf-8 + Expires: Thu, 01 Jan 1970 00:00:00 GMT + Server: Jetty(6.1.21) + Set-Cookie: JSESSIONID=29e1qfeg8g2y;Path=/ + body: 'Execution status: running' diff --git a/src/test/resources/betamax/tapes/abort_execution_as_user_unauthorized.yaml b/src/test/resources/betamax/tapes/abort_execution_as_user_unauthorized.yaml new file mode 100644 index 0000000..6fb5251 --- /dev/null +++ b/src/test/resources/betamax/tapes/abort_execution_as_user_unauthorized.yaml @@ -0,0 +1,20 @@ +!tape +name: abort_execution_as_user_unauthorized +interactions: +- recorded: 2013-03-29T20:34:04.285Z + request: + method: GET + uri: http://rundeck.local:4440/api/5/execution/28/abort?asUser=api-java-client-test-abort-as-user1 + headers: + Host: rundeck.local:4440 + Proxy-Connection: Keep-Alive + User-Agent: RunDeck API Java Client 5 + X-RunDeck-Auth-Token: 9RdEosesKP3se4oV9EKOd4s3RUeUS3ON + response: + status: 200 + headers: + Content-Type: text/xml; charset=utf-8 + Expires: Thu, 01 Jan 1970 00:00:00 GMT + Server: Jetty(6.1.21) + Set-Cookie: JSESSIONID=1i3vnb19oksh7;Path=/ + body: 'Execution status: running' diff --git a/src/test/resources/betamax/tapes/trigger_adhoc_command.yaml b/src/test/resources/betamax/tapes/trigger_adhoc_command.yaml new file mode 100644 index 0000000..586ddc8 --- /dev/null +++ b/src/test/resources/betamax/tapes/trigger_adhoc_command.yaml @@ -0,0 +1,35 @@ +!tape +name: trigger_adhoc_command +interactions: +- recorded: 2013-03-29T19:57:23.492Z + request: + method: GET + uri: http://rundeck.local:4440/api/5/run/command?project=test&exec=echo+test+trigger_adhoc_command + headers: + Host: rundeck.local:4440 + Proxy-Connection: Keep-Alive + User-Agent: RunDeck API Java Client 5 + X-RunDeck-Auth-Token: 9RdEosesKP3se4oV9EKOd4s3RUeUS3ON + response: + status: 200 + headers: + Content-Type: text/xml; charset=utf-8 + Expires: Thu, 01 Jan 1970 00:00:00 GMT + Server: Jetty(6.1.21) + Set-Cookie: JSESSIONID=1ectxi0o7trf4;Path=/ + body: Immediate execution scheduled (23) +- recorded: 2013-03-29T19:57:23.527Z + request: + method: GET + uri: http://rundeck.local:4440/api/5/execution/23 + headers: + Host: rundeck.local:4440 + Proxy-Connection: Keep-Alive + User-Agent: RunDeck API Java Client 5 + X-RunDeck-Auth-Token: 9RdEosesKP3se4oV9EKOd4s3RUeUS3ON + response: + status: 200 + headers: + Content-Type: text/xml; charset=utf-8 + Server: Jetty(6.1.21) + body: admin2013-03-29T19:57:23Z2013-03-29T19:57:23Zecho test trigger_adhoc_command diff --git a/src/test/resources/betamax/tapes/trigger_adhoc_command_as_user.yaml b/src/test/resources/betamax/tapes/trigger_adhoc_command_as_user.yaml new file mode 100644 index 0000000..f9815e8 --- /dev/null +++ b/src/test/resources/betamax/tapes/trigger_adhoc_command_as_user.yaml @@ -0,0 +1,35 @@ +!tape +name: trigger_adhoc_command_as_user +interactions: +- recorded: 2013-03-29T20:01:11.212Z + request: + method: GET + uri: http://rundeck.local:4440/api/5/run/command?project=test&exec=echo+test+trigger_adhoc_command_as_user&asUser=api-java-client-test-run-command-as-user1 + headers: + Host: rundeck.local:4440 + Proxy-Connection: Keep-Alive + User-Agent: RunDeck API Java Client 5 + X-RunDeck-Auth-Token: 9RdEosesKP3se4oV9EKOd4s3RUeUS3ON + response: + status: 200 + headers: + Content-Type: text/xml; charset=utf-8 + Expires: Thu, 01 Jan 1970 00:00:00 GMT + Server: Jetty(6.1.21) + Set-Cookie: JSESSIONID=6xc6z14fisi7;Path=/ + body: Immediate execution scheduled (24) +- recorded: 2013-03-29T20:01:11.252Z + request: + method: GET + uri: http://rundeck.local:4440/api/5/execution/24 + headers: + Host: rundeck.local:4440 + Proxy-Connection: Keep-Alive + User-Agent: RunDeck API Java Client 5 + X-RunDeck-Auth-Token: 9RdEosesKP3se4oV9EKOd4s3RUeUS3ON + response: + status: 200 + headers: + Content-Type: text/xml; charset=utf-8 + Server: Jetty(6.1.21) + body: api-java-client-test-run-command-as-user12013-03-29T20:01:11Z2013-03-29T20:01:11Zecho test trigger_adhoc_command_as_user diff --git a/src/test/resources/betamax/tapes/trigger_adhoc_command_as_user_unauthorized.yaml b/src/test/resources/betamax/tapes/trigger_adhoc_command_as_user_unauthorized.yaml new file mode 100644 index 0000000..4c46a6b --- /dev/null +++ b/src/test/resources/betamax/tapes/trigger_adhoc_command_as_user_unauthorized.yaml @@ -0,0 +1,18 @@ +!tape +name: trigger_adhoc_command_as_user_unauthorized +interactions: +- recorded: 2013-03-29T20:29:44.099Z + request: + method: GET + uri: http://rundeck.local:4440/api/5/run/command?project=test&exec=echo+test+trigger_adhoc_command_as_user&asUser=api-java-client-test-run-command-as-user1 + headers: + Host: rundeck.local:4440 + Proxy-Connection: Keep-Alive + User-Agent: RunDeck API Java Client 5 + X-RunDeck-Auth-Token: 9RdEosesKP3se4oV9EKOd4s3RUeUS3ON + response: + status: 200 + headers: + Content-Type: text/xml; charset=utf-8 + Server: Jetty(6.1.21) + body: Not authorized for action "Run as User" for Run Adhoc diff --git a/src/test/resources/betamax/tapes/trigger_adhoc_script.yaml b/src/test/resources/betamax/tapes/trigger_adhoc_script.yaml new file mode 100644 index 0000000..af6156c --- /dev/null +++ b/src/test/resources/betamax/tapes/trigger_adhoc_script.yaml @@ -0,0 +1,41 @@ +!tape +name: trigger_adhoc_script +interactions: +- recorded: 2013-03-29T20:13:23.329Z + request: + method: POST + uri: http://rundeck.local:4440/api/5/run/script?project=test + headers: + Content-Type: multipart/form-data; boundary=cUrn319n4IJx75QQyRUt6TuRTCi4yW3sKC + Host: rundeck.local:4440 + Proxy-Connection: Keep-Alive + Transfer-Encoding: chunked + User-Agent: RunDeck API Java Client 5 + X-RunDeck-Auth-Token: 9RdEosesKP3se4oV9EKOd4s3RUeUS3ON + response: + status: 200 + headers: + Content-Type: text/xml; charset=utf-8 + Expires: Thu, 01 Jan 1970 00:00:00 GMT + Server: Jetty(6.1.21) + Set-Cookie: JSESSIONID=1eu6rbdmflmww;Path=/ + body: Immediate execution scheduled (25) +- recorded: 2013-03-29T20:13:23.386Z + request: + method: GET + uri: http://rundeck.local:4440/api/5/execution/25 + headers: + Host: rundeck.local:4440 + Proxy-Connection: Keep-Alive + User-Agent: RunDeck API Java Client 5 + X-RunDeck-Auth-Token: 9RdEosesKP3se4oV9EKOd4s3RUeUS3ON + response: + status: 200 + headers: + Content-Type: text/xml; charset=utf-8 + Server: Jetty(6.1.21) + body: 'admin2013-03-29T20:13:23Z#!/bin/bash + + echo test trigger_adhoc_script + + ' diff --git a/src/test/resources/betamax/tapes/trigger_adhoc_script_as_user.yaml b/src/test/resources/betamax/tapes/trigger_adhoc_script_as_user.yaml new file mode 100644 index 0000000..52cafd0 --- /dev/null +++ b/src/test/resources/betamax/tapes/trigger_adhoc_script_as_user.yaml @@ -0,0 +1,41 @@ +!tape +name: trigger_adhoc_script_as_user +interactions: +- recorded: 2013-03-29T20:15:40.223Z + request: + method: POST + uri: http://rundeck.local:4440/api/5/run/script?project=test&asUser=api-java-client-test-adhoc-script-as-user1 + headers: + Content-Type: multipart/form-data; boundary=PtMlGUvOZTAvTtuFv7N4aCTeVwVXGBU7137 + Host: rundeck.local:4440 + Proxy-Connection: Keep-Alive + Transfer-Encoding: chunked + User-Agent: RunDeck API Java Client 5 + X-RunDeck-Auth-Token: 9RdEosesKP3se4oV9EKOd4s3RUeUS3ON + response: + status: 200 + headers: + Content-Type: text/xml; charset=utf-8 + Expires: Thu, 01 Jan 1970 00:00:00 GMT + Server: Jetty(6.1.21) + Set-Cookie: JSESSIONID=130cx6ycqxdnz;Path=/ + body: Immediate execution scheduled (26) +- recorded: 2013-03-29T20:15:40.291Z + request: + method: GET + uri: http://rundeck.local:4440/api/5/execution/26 + headers: + Host: rundeck.local:4440 + Proxy-Connection: Keep-Alive + User-Agent: RunDeck API Java Client 5 + X-RunDeck-Auth-Token: 9RdEosesKP3se4oV9EKOd4s3RUeUS3ON + response: + status: 200 + headers: + Content-Type: text/xml; charset=utf-8 + Server: Jetty(6.1.21) + body: 'api-java-client-test-adhoc-script-as-user12013-03-29T20:15:40Z#!/bin/bash + + echo test trigger_adhoc_script + + ' diff --git a/src/test/resources/betamax/tapes/trigger_adhoc_script_as_user_unauthorized.yaml b/src/test/resources/betamax/tapes/trigger_adhoc_script_as_user_unauthorized.yaml new file mode 100644 index 0000000..c1459c7 --- /dev/null +++ b/src/test/resources/betamax/tapes/trigger_adhoc_script_as_user_unauthorized.yaml @@ -0,0 +1,38 @@ +!tape +name: trigger_adhoc_script_as_user_unauthorized +interactions: +- recorded: 2013-03-29T20:31:13.669Z + request: + method: POST + uri: http://rundeck.local:4440/api/5/run/script?project=test&asUser=api-java-client-test-adhoc-script-as-user1 + headers: + Content-Type: multipart/form-data; boundary=jnpXLHXeLpI_iLu2EioWePNLmLGmsdwKv + Host: rundeck.local:4440 + Proxy-Connection: Keep-Alive + Transfer-Encoding: chunked + User-Agent: RunDeck API Java Client 5 + X-RunDeck-Auth-Token: 9RdEosesKP3se4oV9EKOd4s3RUeUS3ON + response: + status: 302 + headers: + Expires: Thu, 01 Jan 1970 00:00:00 GMT + Location: http://rundeck.local:4440/api/error;jsessionid=1hbsc2k5khghe + Server: Jetty(6.1.21) + Set-Cookie: JSESSIONID=1hbsc2k5khghe;Path=/ +- recorded: 2013-03-29T20:31:13.694Z + request: + method: GET + uri: http://rundeck.local:4440/api/error;jsessionid=1hbsc2k5khghe + headers: + Cookie: JSESSIONID=1hbsc2k5khghe + Cookie2: $Version=1 + Host: rundeck.local:4440 + Proxy-Connection: Keep-Alive + User-Agent: RunDeck API Java Client 5 + X-RunDeck-Auth-Token: 9RdEosesKP3se4oV9EKOd4s3RUeUS3ON + response: + status: 200 + headers: + Content-Type: text/xml; charset=utf-8 + Server: Jetty(6.1.21) + body: Not authorized for action "Run as User" for Run Adhoc diff --git a/src/test/resources/betamax/tapes/trigger_job_as_user.yaml b/src/test/resources/betamax/tapes/trigger_job_as_user.yaml new file mode 100644 index 0000000..e131545 --- /dev/null +++ b/src/test/resources/betamax/tapes/trigger_job_as_user.yaml @@ -0,0 +1,20 @@ +!tape +name: trigger_job_as_user +interactions: +- recorded: 2013-03-29T19:43:25.042Z + request: + method: GET + uri: http://rundeck.local:4440/api/5/job/3170ba0e-6093-4b58-94d2-52988aefbfc9/run?asUser=api-java-client-user-test1 + headers: + Host: rundeck.local:4440 + Proxy-Connection: Keep-Alive + User-Agent: RunDeck API Java Client 5 + X-RunDeck-Auth-Token: 9RdEosesKP3se4oV9EKOd4s3RUeUS3ON + response: + status: 200 + headers: + Content-Type: text/xml; charset=utf-8 + Expires: Thu, 01 Jan 1970 00:00:00 GMT + Server: Jetty(6.1.21) + Set-Cookie: JSESSIONID=1he4xdn8b71lg;Path=/ + body: api-java-client-user-test12013-03-29T19:43:24Ztest job 1testecho hi there ${job.username} ; sleep 90 diff --git a/src/test/resources/betamax/tapes/trigger_job_as_user_unauthorized.yaml b/src/test/resources/betamax/tapes/trigger_job_as_user_unauthorized.yaml new file mode 100644 index 0000000..4705479 --- /dev/null +++ b/src/test/resources/betamax/tapes/trigger_job_as_user_unauthorized.yaml @@ -0,0 +1,20 @@ +!tape +name: trigger_job_as_user_unauthorized +interactions: +- recorded: 2013-03-29T20:22:45.001Z + request: + method: GET + uri: http://rundeck.local:4440/api/5/job/3170ba0e-6093-4b58-94d2-52988aefbfc9/run?asUser=api-java-client-user-test2 + headers: + Host: rundeck.local:4440 + Proxy-Connection: Keep-Alive + User-Agent: RunDeck API Java Client 5 + X-RunDeck-Auth-Token: 9RdEosesKP3se4oV9EKOd4s3RUeUS3ON + response: + status: 200 + headers: + Content-Type: text/xml; charset=utf-8 + Expires: Thu, 01 Jan 1970 00:00:00 GMT + Server: Jetty(6.1.21) + Set-Cookie: JSESSIONID=1b21l1aznu12a;Path=/ + body: Not authorized for action "Run as User" for Job ID 3170ba0e-6093-4b58-94d2-52988aefbfc9 diff --git a/src/test/resources/betamax/tapes/trigger_job_basic.yaml b/src/test/resources/betamax/tapes/trigger_job_basic.yaml new file mode 100644 index 0000000..974b66b --- /dev/null +++ b/src/test/resources/betamax/tapes/trigger_job_basic.yaml @@ -0,0 +1,20 @@ +!tape +name: trigger_job_basic +interactions: +- recorded: 2013-03-29T19:39:04.442Z + request: + method: GET + uri: http://rundeck.local:4440/api/5/job/3170ba0e-6093-4b58-94d2-52988aefbfc9/run + headers: + Host: rundeck.local:4440 + Proxy-Connection: Keep-Alive + User-Agent: RunDeck API Java Client 5 + X-RunDeck-Auth-Token: 9RdEosesKP3se4oV9EKOd4s3RUeUS3ON + response: + status: 200 + headers: + Content-Type: text/xml; charset=utf-8 + Expires: Thu, 01 Jan 1970 00:00:00 GMT + Server: Jetty(6.1.21) + Set-Cookie: JSESSIONID=pyljht19673c;Path=/ + body: admin2013-03-29T19:39:04Ztest job 1testecho hi there ${job.username} ; sleep 90