From deee2ac0b17e85672c68587a14bb025ae4fc5f70 Mon Sep 17 00:00:00 2001
From: Greg Schueler
- * Deprecation Warning: These methods which take multiple arguments are deprecated in
- * favor of single argument versions, and associated Builder classes to generate them.
- * These methods will be removed in version 10 of this library:
- *
- *
- *
* You have 2 methods for authentication : login-based or token-based. If you want to use the first, you need to provide * both a "login" and a "password". Otherwise, just provide a "token" (also called "auth-token"). See the RunDeck * documentation for generating such a token.
@@ -123,10 +104,10 @@ public class RundeckClient implements Serializable { public static final transient String API_ENDPOINT = API + API_VERSION; /** Default value for the "pooling interval" used when running jobs/commands/scripts */ - private static final transient long DEFAULT_POOLING_INTERVAL = 5; + public static final transient long DEFAULT_POOLING_INTERVAL = 5; /** Default unit of the "pooling interval" used when running jobs/commands/scripts */ - private static final transient TimeUnit DEFAULT_POOLING_UNIT = TimeUnit.SECONDS; + public static final TimeUnit DEFAULT_POOLING_UNIT = TimeUnit.SECONDS; /** URL of the RunDeck instance ("http://localhost:4440", "http://rundeck.your-compagny.com/", etc) */ private final String url; @@ -202,7 +183,7 @@ public class RundeckClient implements Serializable { * @throws IllegalArgumentException if the url or token is blank (null, empty or whitespace) * @deprecated Use the builder {@link RundeckClientBuilder}, this method will not be public in version 10 of this library. */ - public RundeckClient(String url, String token, String sessionID, boolean useToken) throws IllegalArgumentException { + private RundeckClient(String url, String token, String sessionID, boolean useToken) throws IllegalArgumentException { this(url); if(useToken){ @@ -260,7 +241,7 @@ public class RundeckClient implements Serializable { } /** - * @deprecated Use {@link #testAuth()} + * @deprecated Use {@link #testAuth()}, will be removed in version 12 of this library. * @see #testAuth() */ @Deprecated @@ -635,193 +616,6 @@ public class RundeckClient implements Serializable { return new ApiCall(this).get(new ApiPathBuilder("/job/", jobId).param("format", format)); } - /** - * Import the definitions of jobs, from the given file - * - * @param filename of the file containing the jobs definitions - mandatory - * @param fileType type of the file. See {@link FileType} - mandatory - * @return a {@link RundeckJobsImportResult} instance - won't be null - * @throws RundeckApiException in case of error when calling the API - * @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 filename or fileType is blank (null, empty or whitespace), or the - * fileType is invalid - * @throws IOException if we failed to read the file - * @see #importJobs(InputStream, String) - * @see #importJobs(String, FileType, RundeckJobsImportMethod) - * @deprecated use {@link #importJobs(RundeckJobsImport)}, this method will be removed in version 10 of this library. - */ - public RundeckJobsImportResult importJobs(String filename, String fileType) throws RundeckApiException, - RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, IOException { - AssertUtil.notBlank(fileType, "fileType is mandatory to import jobs !"); - return importJobs(filename, FileType.valueOf(StringUtils.upperCase(fileType))); - } - - /** - * Import the definitions of jobs, from the given file - * - * @param filename of the file containing the jobs definitions - mandatory - * @param fileType type of the file. See {@link FileType} - mandatory - * @return a {@link RundeckJobsImportResult} instance - won't be null - * @throws RundeckApiException in case of error when calling the API - * @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 filename is blank (null, empty or whitespace), or the fileType is null - * @throws IOException if we failed to read the file - * @see #importJobs(InputStream, FileType) - * @see #importJobs(String, FileType, RundeckJobsImportMethod) - * @deprecated use {@link #importJobs(RundeckJobsImport)}, this method will be removed in version 10 of this - * library. - */ - public RundeckJobsImportResult importJobs(String filename, FileType fileType) throws RundeckApiException, - RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, IOException { - return importJobs(filename, fileType, (RundeckJobsImportMethod) null); - } - - /** - * Import the definitions of jobs, from the given file, using the given behavior - * - * @param filename of the file containing the jobs definitions - mandatory - * @param fileType type of the file. See {@link FileType} - mandatory - * @param importBehavior see {@link RundeckJobsImportMethod} - * @return a {@link RundeckJobsImportResult} instance - won't be null - * @throws RundeckApiException in case of error when calling the API - * @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 filename or fileType is blank (null, empty or whitespace), or the - * fileType or behavior is not valid - * @throws IOException if we failed to read the file - * @see #importJobs(InputStream, String, String) - * @see #importJobs(String, FileType, RundeckJobsImportMethod) - * @deprecated use {@link #importJobs(RundeckJobsImport)}, this method will be removed in version 10 of this - * library. - */ - public RundeckJobsImportResult importJobs(String filename, String fileType, String importBehavior) - throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, - IOException { - AssertUtil.notBlank(fileType, "fileType is mandatory to import jobs !"); - return importJobs(filename, - FileType.valueOf(StringUtils.upperCase(fileType)), - RundeckJobsImportMethod.valueOf(StringUtils.upperCase(importBehavior))); - } - - /** - * Import the definitions of jobs, from the given file, using the given behavior - * - * @param filename of the file containing the jobs definitions - mandatory - * @param fileType type of the file. See {@link FileType} - mandatory - * @param importBehavior see {@link RundeckJobsImportMethod} - * @return a {@link RundeckJobsImportResult} instance - won't be null - * @throws RundeckApiException in case of error when calling the API - * @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 filename is blank (null, empty or whitespace), or the fileType is null - * @throws IOException if we failed to read the file - * @see #importJobs(InputStream, FileType, RundeckJobsImportMethod) - * @deprecated use {@link #importJobs(String, RundeckJobsImport)}, this method will be removed in version 10 of - * this library. - */ - public RundeckJobsImportResult importJobs(String filename, FileType fileType, RundeckJobsImportMethod importBehavior) - throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, - IOException { - AssertUtil.notBlank(filename, "filename (of jobs file) is mandatory to import jobs !"); - FileInputStream stream = null; - try { - stream = FileUtils.openInputStream(new File(filename)); - return importJobs(stream, fileType, importBehavior); - } finally { - IOUtils.closeQuietly(stream); - } - } - - /** - * Import the definitions of jobs, from the given input stream - * - * @param stream inputStream for reading the definitions - mandatory - * @param fileType type of the file. See {@link FileType} - mandatory - * @return a {@link RundeckJobsImportResult} instance - won't be null - * @throws RundeckApiException in case of error when calling the API - * @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 stream is null, or the fileType is blank (null, empty or whitespace) or - * invalid - * @see #importJobs(String, String) - * @see #importJobs(InputStream, FileType, RundeckJobsImportMethod) - * @deprecated use {@link #importJobs(RundeckJobsImport)}, this method will be removed in version 10 of this - * library. - */ - public RundeckJobsImportResult importJobs(InputStream stream, String fileType) throws RundeckApiException, - RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { - AssertUtil.notBlank(fileType, "fileType is mandatory to import jobs !"); - return importJobs(stream, FileType.valueOf(StringUtils.upperCase(fileType))); - } - - /** - * Import the definitions of jobs, from the given input stream - * - * @param stream inputStream for reading the definitions - mandatory - * @param fileType type of the file. See {@link FileType} - mandatory - * @return a {@link RundeckJobsImportResult} instance - won't be null - * @throws RundeckApiException in case of error when calling the API - * @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 stream or fileType is null - * @see #importJobs(String, FileType) - * @see #importJobs(InputStream, FileType, RundeckJobsImportMethod) - * @deprecated use {@link #importJobs(RundeckJobsImport)}, this method will be removed in version 10 of this - * library. - */ - public RundeckJobsImportResult importJobs(InputStream stream, FileType fileType) throws RundeckApiException, - RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { - return importJobs(stream, fileType, (RundeckJobsImportMethod) null); - } - - /** - * Import the definitions of jobs, from the given input stream, using the given behavior - * - * @param stream inputStream for reading the definitions - mandatory - * @param fileType type of the file. See {@link FileType} - mandatory - * @param importBehavior see {@link RundeckJobsImportMethod} - * @return a {@link RundeckJobsImportResult} instance - won't be null - * @throws RundeckApiException in case of error when calling the API - * @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 stream is null, or the fileType is blank (null, empty or whitespace), or - * the fileType or behavior is not valid - * @see #importJobs(String, String, String) - * @see #importJobs(InputStream, FileType, RundeckJobsImportMethod) - * @deprecated use {@link #importJobs(RundeckJobsImport)}, this method will be removed in version 10 of this - * library. - */ - public RundeckJobsImportResult importJobs(InputStream stream, String fileType, String importBehavior) - throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { - AssertUtil.notBlank(fileType, "fileType is mandatory to import jobs !"); - return importJobs(stream, - FileType.valueOf(StringUtils.upperCase(fileType)), - RundeckJobsImportMethod.valueOf(StringUtils.upperCase(importBehavior))); - } - - /** - * Import the definitions of jobs, from the given input stream, using the given behavior - * - * @param stream inputStream for reading the definitions - mandatory - * @param fileType type of the file. See {@link FileType} - mandatory - * @param importBehavior see {@link RundeckJobsImportMethod} - * @return a {@link RundeckJobsImportResult} instance - won't be null - * @throws RundeckApiException in case of error when calling the API - * @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 stream or fileType is null - * @see #importJobs(String, FileType, RundeckJobsImportMethod) - * @deprecated use {@link #importJobs(RundeckJobsImport)}, this method will be removed in version 10 of this - * library. - */ - public RundeckJobsImportResult importJobs(InputStream stream, FileType fileType, - RundeckJobsImportMethod importBehavior) throws RundeckApiException, RundeckApiLoginException, - RundeckApiTokenException, IllegalArgumentException { - return importJobs(RundeckJobsImportBuilder.builder().setStream(stream).setFileType(fileType) - .setJobsImportMethod(importBehavior).build()); - } /** * Import the definitions of jobs, from the given input stream, using the given behavior @@ -957,93 +751,6 @@ public class RundeckClient implements Serializable { new BulkDeleteParser("result/deleteJobs")); } - /** - * 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 - * @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, Properties, Properties) - * @see #runJob(String) - * @deprecated use {@link #triggerJob(RunJob)}, this method will be removed in version 10 of this library - */ - public RundeckExecution triggerJob(String jobId) throws RundeckApiException, RundeckApiLoginException, - RundeckApiTokenException, IllegalArgumentException { - return triggerJob(jobId, 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}. - * @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, Properties, Properties) - * @see #runJob(String, Properties) - * @deprecated use {@link #triggerJob(RunJob)}, this method will be removed in version 10 of this library - */ - public RundeckExecution triggerJob(String jobId, Properties options) throws RundeckApiException, - RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { - return triggerJob(jobId, options, 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} - * @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) - * @deprecated use {@link #triggerJob(RunJob)}, this method will be removed in version 10 of this library - */ - 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) - * @deprecated use {@link #triggerJob(RunJob)}, this method will be removed in version 10 of this library - */ - public RundeckExecution triggerJob(String jobId, Properties options, Properties nodeFilters, String asUser) - throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { - return triggerJob(RunJobBuilder.builder() - .setJobId(jobId) - .setOptions(options) - .setNodeFilters(nodeFilters) - .setAsUser(asUser) - .build()); - } /** * Trigger the execution of a RunDeck job (identified by the given ID), and return immediately (without waiting the * end of the job execution) @@ -1069,72 +776,6 @@ public class RundeckClient implements Serializable { return new ApiCall(this).get(apiPath, new ExecutionParser("result/executions/execution")); } - /** - * 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 (every 5 seconds) to know if the execution is finished (or - * aborted) or is still running. - * - * @param jobId identifier of the job - mandatory - * @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) - * @see #runJob(String, Properties, Properties, long, TimeUnit) - * @deprecated use {@link #runJob(RunJob, long, java.util.concurrent.TimeUnit)}, - * this method will be removed in version 10 of this library - */ - public RundeckExecution runJob(String jobId) throws RundeckApiException, RundeckApiLoginException, - RundeckApiTokenException, IllegalArgumentException { - return runJob(jobId, null); - } - - /** - * 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 (every 5 seconds) 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}. - * @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) - * @deprecated use {@link #runJob(RunJob, long, java.util.concurrent.TimeUnit)}, - * this method will be removed in version 10 of this library - */ - public RundeckExecution runJob(String jobId, Properties options) throws RundeckApiException, - RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { - return runJob(jobId, options, null); - } - - /** - * 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 (every 5 seconds) 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} - * @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, Properties) - * @see #runJob(String, Properties, Properties, long, TimeUnit) - * @deprecated use {@link #runJob(RunJob, long, java.util.concurrent.TimeUnit)}, - * this method will be removed in version 10 of this library - */ - public RundeckExecution runJob(String jobId, Properties options, Properties nodeFilters) - throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { - return runJob(jobId, options, nodeFilters, DEFAULT_POOLING_INTERVAL, DEFAULT_POOLING_UNIT); - } /** * Run a RunDeck job (identified by the given ID), and wait until its execution is finished (or aborted) to return. @@ -1156,87 +797,6 @@ public class RundeckClient implements Serializable { RundeckApiTokenException, IllegalArgumentException { return runJob(runJob, DEFAULT_POOLING_INTERVAL, DEFAULT_POOLING_UNIT); } - /** - * 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 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) - * @deprecated use {@link #runJob(RunJob, long, java.util.concurrent.TimeUnit)}, - * this method will be removed in version 10 of this library - */ - public RundeckExecution runJob(String jobId, Properties options, long poolingInterval, TimeUnit poolingUnit) - throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { - return runJob(jobId, options, 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 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) - * @deprecated use {@link #runJob(RunJob, long, java.util.concurrent.TimeUnit)}, - * this method will be removed in version 10 of this library - */ - 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) - * @deprecated use {@link #runJob(RunJob, long, java.util.concurrent.TimeUnit)}, this method will be removed in version 10 of this library - */ - public RundeckExecution runJob(String jobId, Properties options, Properties nodeFilters, String asUser, long poolingInterval, - TimeUnit poolingUnit) throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, - IllegalArgumentException { - return runJob(RunJobBuilder.builder() - .setJobId(jobId) - .setOptions(options) - .setNodeFilters(nodeFilters) - .setAsUser(asUser) - .build(), poolingInterval, poolingUnit); - } /** * Run a RunDeck job (identified by the given ID), and wait until its execution is finished (or aborted) to return. @@ -1283,101 +843,7 @@ public class RundeckClient implements Serializable { * Ad-hoc commands */ - /** - * Trigger the execution of an ad-hoc command, and return immediately (without waiting the end of the execution). - * The command will not be dispatched to nodes, but be executed on the RunDeck server. - * - * @param project name of the project - mandatory - * @param command to be executed - mandatory - * @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, Properties, Integer, Boolean) - * @see #runAdhocCommand(String, String) - * @deprecated use {@link #triggerAdhocCommand(RunAdhocCommand)}, will be removed in version 10 of this library - */ - public RundeckExecution triggerAdhocCommand(String project, String command) throws RundeckApiException, - RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { - return triggerAdhocCommand(project, command, 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} - * @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, Properties, Integer, Boolean) - * @see #runAdhocCommand(String, String, Properties) - * @deprecated use {@link #triggerAdhocCommand(RunAdhocCommand)}, will be removed in version 10 of this library - */ - public RundeckExecution triggerAdhocCommand(String project, String command, Properties nodeFilters) - throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { - return triggerAdhocCommand(project, command, nodeFilters, null, 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 - * @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) - * @deprecated use {@link #triggerAdhocCommand(RunAdhocCommand)}, will be removed in version 10 of this library - */ - 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) - * @deprecated use {@link #triggerAdhocCommand(RunAdhocCommand)}, will be removed in version 10 of this library - */ - public RundeckExecution triggerAdhocCommand(String project, String command, Properties nodeFilters, - Integer nodeThreadcount, Boolean nodeKeepgoing, String asUser) throws RundeckApiException, RundeckApiLoginException, - RundeckApiTokenException, IllegalArgumentException { - return triggerAdhocCommand(RunAdhocCommandBuilder.builder() - .setProject(project) - .setCommand(command) - .setNodeFilters(nodeFilters) - .setNodeThreadcount(nodeThreadcount) - .setNodeKeepgoing(nodeKeepgoing) - .setAsUser(asUser) - .build()); - } /** * 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. @@ -1410,134 +876,6 @@ public class RundeckClient implements Serializable { return getExecution(execution.getId()); } - /** - * 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 (every 5 seconds) to know if the execution is finished (or aborted) or is still - * running. The command will not be dispatched to nodes, but be executed on the RunDeck server. - * - * @param project name of the project - mandatory - * @param command to be executed - mandatory - * @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 #runAdhocCommand(String, String, Properties, Integer, Boolean, long, TimeUnit) - * @see #triggerAdhocCommand(String, String) - * @deprecated use {@link #runAdhocCommand(RunAdhocCommand)}, this method will - * be removed in version 10 of this library - */ - public RundeckExecution runAdhocCommand(String project, String command) throws RundeckApiException, - RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { - return runAdhocCommand(project, command, null); - } - - /** - * 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 not be dispatched to nodes, but be executed on the - * RunDeck server. - * - * @param project name of the project - mandatory - * @param command to be executed - mandatory - * @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 #runAdhocCommand(String, String, Properties, Integer, Boolean, long, TimeUnit) - * @see #triggerAdhocCommand(String, String) - * @deprecated use {@link #runAdhocCommand(RunAdhocCommand, long, java.util.concurrent.TimeUnit)}, this method will - * be removed in version 10 of this library - */ - public RundeckExecution runAdhocCommand(String project, String command, long poolingInterval, TimeUnit poolingUnit) - throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { - return runAdhocCommand(project, command, 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 (every 5 seconds) 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} - * @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 #runAdhocCommand(String, String, Properties, Integer, Boolean, long, TimeUnit) - * @see #triggerAdhocCommand(String, String, Properties) - * @deprecated use {@link #runAdhocCommand(RunAdhocCommand)}, this method will - * be removed in version 10 of this library - */ - public RundeckExecution runAdhocCommand(String project, String command, Properties nodeFilters) - throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { - return runAdhocCommand(project, command, nodeFilters, null, null); - } - - /** - * 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 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 #runAdhocCommand(String, String, Properties, Integer, Boolean, long, TimeUnit) - * @see #triggerAdhocCommand(String, String, Properties) - * @deprecated use {@link #runAdhocCommand(RunAdhocCommand, long, java.util.concurrent.TimeUnit)}, this method will - * be removed in version 10 of this library - */ - public RundeckExecution runAdhocCommand(String project, String command, Properties nodeFilters, - long poolingInterval, TimeUnit poolingUnit) throws RundeckApiException, RundeckApiLoginException, - RundeckApiTokenException, IllegalArgumentException { - return runAdhocCommand(project, command, nodeFilters, null, 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 (every 5 seconds) 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 - * @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 #runAdhocCommand(String, String, Properties, Integer, Boolean, long, TimeUnit) - * @see #triggerAdhocCommand(String, String, Properties, Integer, Boolean) - * @deprecated use {@link #runAdhocCommand(RunAdhocCommand)}, this method will - * be removed in version 10 of this library - */ - public RundeckExecution runAdhocCommand(String project, String command, Properties nodeFilters, - Integer nodeThreadcount, Boolean nodeKeepgoing) throws RundeckApiException, RundeckApiLoginException, - RundeckApiTokenException, IllegalArgumentException { - return runAdhocCommand(project, - command, - nodeFilters, - nodeThreadcount, - nodeKeepgoing, - DEFAULT_POOLING_INTERVAL, - DEFAULT_POOLING_UNIT); - } /** * Run an ad-hoc command, and wait until its execution is finished (or aborted) to return. We will poll the RunDeck @@ -1560,70 +898,6 @@ public class RundeckClient implements Serializable { DEFAULT_POOLING_UNIT); } - /** - * 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) - * @deprecated use {@link #runAdhocCommand(RunAdhocCommand, long, java.util.concurrent.TimeUnit)}, this method will - * be removed in version 10 of this library - */ - 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) - * @deprecated use {@link #runAdhocCommand(RunAdhocCommand, long, java.util.concurrent.TimeUnit)}, this method will - * be removed in version 10 of this library - */ - public RundeckExecution runAdhocCommand(String project, String command, Properties nodeFilters, - Integer nodeThreadcount, Boolean nodeKeepgoing, String asUser, long poolingInterval, TimeUnit poolingUnit) - throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { - return runAdhocCommand(RunAdhocCommandBuilder.builder() - .setProject(project) - .setCommand(command) - .setNodeFilters(nodeFilters) - .setNodeThreadcount(nodeThreadcount) - .setNodeKeepgoing(nodeKeepgoing) - .setAsUser(asUser) - .build(), 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 @@ -1666,323 +940,6 @@ public class RundeckClient implements Serializable { * Ad-hoc scripts */ - /** - * Trigger the execution of an ad-hoc script, and return immediately (without waiting the end of the execution). The - * script will not be dispatched to nodes, but be executed on the RunDeck server. - * - * @param project name of the project - mandatory - * @param scriptFilename filename of the script to be executed - mandatory - * @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, String, Properties, Properties, Integer, Boolean) - * @see #runAdhocScript(String, String) - * @deprecated use {@link #triggerAdhocScript(RunAdhocScript)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution triggerAdhocScript(String project, String scriptFilename) throws RundeckApiException, - RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, IOException { - return triggerAdhocScript(project, scriptFilename, null); - } - - /** - * Trigger the execution of an ad-hoc script, and return immediately (without waiting the end of the execution). The - * script will not be dispatched to nodes, but be executed on the RunDeck server. - * - * @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}. - * @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, String, Properties, Properties, Integer, Boolean) - * @see #runAdhocScript(String, String, Properties) - * @deprecated use {@link #triggerAdhocScript(RunAdhocScript)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution triggerAdhocScript(String project, String scriptFilename, Properties options) - throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, - IOException { - return triggerAdhocScript(project, scriptFilename, options, 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} - * @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, String, Properties, Properties, Integer, Boolean) - * @see #runAdhocScript(String, String, Properties, Properties) - * @deprecated use {@link #triggerAdhocScript(RunAdhocScript)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution triggerAdhocScript(String project, String scriptFilename, Properties options, - Properties nodeFilters) throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, - IllegalArgumentException, IOException { - return triggerAdhocScript(project, scriptFilename, options, nodeFilters, null, 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) - * @deprecated use {@link #triggerAdhocScript(RunAdhocScript)}, this method will be - * removed in version 10 of this library - */ - 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) - * @deprecated use {@link #triggerAdhocScript(RunAdhocScript)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution triggerAdhocScript(String project, String scriptFilename, Properties options, - Properties nodeFilters, Integer nodeThreadcount, Boolean nodeKeepgoing,String asUser) throws RundeckApiException, - RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, IOException { - return triggerAdhocScript(project, scriptFilename, ParametersUtil.generateArgString(options), nodeFilters, - nodeThreadcount, nodeKeepgoing, asUser); - } - /** - * 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 argString arguments of the script - optional. - * @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) - * @deprecated use {@link #triggerAdhocScript(RunAdhocScript)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution triggerAdhocScript(String project, String scriptFilename, String argString, - 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(RunAdhocScriptBuilder.builder() - .setProject(project) - .setScript(stream) - .setNodeFilters(nodeFilters) - .setArgString(argString) - .setNodeThreadcount(nodeThreadcount) - .setNodeKeepgoing(nodeKeepgoing) - .setAsUser(asUser) - .build()); - } finally { - IOUtils.closeQuietly(stream); - } - } - - /** - * Trigger the execution of an ad-hoc script, and return immediately (without waiting the end of the execution). The - * script will not be dispatched to nodes, but be executed on the RunDeck server. - * - * @param project name of the project - mandatory - * @param script inputStream for reading the script to be executed - mandatory - * @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, InputStream, Properties, Properties, Integer, Boolean) - * @see #runAdhocScript(String, InputStream) - * @deprecated use {@link #triggerAdhocScript(RunAdhocScript)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution triggerAdhocScript(String project, InputStream script) throws RundeckApiException, - RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { - return triggerAdhocScript(project, script, null); - } - - /** - * Trigger the execution of an ad-hoc script, and return immediately (without waiting the end of the execution). The - * script will not be dispatched to nodes, but be executed on the RunDeck server. - * - * @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}. - * @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, InputStream, Properties, Properties, Integer, Boolean) - * @see #runAdhocScript(String, InputStream, Properties) - * @deprecated use {@link #triggerAdhocScript(RunAdhocScript)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution triggerAdhocScript(String project, InputStream script, Properties options) - throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { - return triggerAdhocScript(project, script, options, 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} - * @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, InputStream, Properties, Properties, Integer, Boolean) - * @see #runAdhocScript(String, InputStream, Properties, Properties) - * @deprecated use {@link #triggerAdhocScript(RunAdhocScript)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution triggerAdhocScript(String project, InputStream script, Properties options, - Properties nodeFilters) throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, - IllegalArgumentException { - return triggerAdhocScript(project, script, options, nodeFilters, null, 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) - * @deprecated use {@link #triggerAdhocScript(RunAdhocScript)}, this method will be - * removed in version 10 of this library - */ - 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) - * @deprecated use {@link #triggerAdhocScript(RunAdhocScript)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution triggerAdhocScript(String project, InputStream script, Properties options, - Properties nodeFilters, Integer nodeThreadcount, Boolean nodeKeepgoing, String asUser) throws RundeckApiException, - RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { - return triggerAdhocScript(project, script, ParametersUtil.generateArgString(options), nodeFilters, - nodeThreadcount, nodeKeepgoing, asUser); - } - /** - * 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 argString arguments of the script - optional. - * @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) - * @deprecated use {@link #triggerAdhocScript(RunAdhocScript)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution triggerAdhocScript(String project, InputStream script, String argString, - Properties nodeFilters, Integer nodeThreadcount, Boolean nodeKeepgoing, String asUser) throws RundeckApiException, - RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException { - return triggerAdhocScript(RunAdhocScriptBuilder.builder() - .setProject(project) - .setScript(script) - .setNodeFilters(nodeFilters) - .setArgString(argString) - .setNodeThreadcount(nodeThreadcount) - .setNodeKeepgoing(nodeKeepgoing) - .setAsUser(asUser) - .build()); - } /** * Trigger the execution of an ad-hoc script read from a file, and return immediately (without waiting the end of @@ -2053,440 +1010,6 @@ public class RundeckClient implements Serializable { return getExecution(execution.getId()); } - /** - * 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 (every 5 seconds) to know if the execution is finished (or aborted) or is still - * running. The script will not be dispatched to nodes, but be executed on the RunDeck server. - * - * @param project name of the project - mandatory - * @param scriptFilename filename of the script to be executed - mandatory - * @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 scriptFilename is blank (null, empty or whitespace) - * @throws IOException if we failed to read the file - * @see #runAdhocScript(String, String, Properties, Properties, Integer, Boolean, long, TimeUnit) - * @see #triggerAdhocScript(String, String) - * @deprecated use {@link #runAdhocScript(RunAdhocScript)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution runAdhocScript(String project, String scriptFilename) throws RundeckApiException, - RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, IOException { - return runAdhocScript(project, scriptFilename, null); - } - - /** - * 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 not be dispatched to nodes, but be executed on the - * RunDeck server. - * - * @param project name of the project - mandatory - * @param scriptFilename filename of the script to be executed - mandatory - * @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 scriptFilename is blank (null, empty or whitespace) - * @throws IOException if we failed to read the file - * @see #runAdhocScript(String, String, Properties, Properties, Integer, Boolean, long, TimeUnit) - * @see #triggerAdhocScript(String, String) - * @deprecated use {@link #runAdhocScript(RunAdhocScript, long, java.util.concurrent.TimeUnit)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution runAdhocScript(String project, String scriptFilename, long poolingInterval, - TimeUnit poolingUnit) throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, - IllegalArgumentException, IOException { - return runAdhocScript(project, scriptFilename, 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 (every 5 seconds) to know if the execution is finished (or aborted) or is still - * running. The script will not be dispatched to nodes, but be executed on the RunDeck server. - * - * @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}. - * @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 scriptFilename is blank (null, empty or whitespace) - * @throws IOException if we failed to read the file - * @see #runAdhocScript(String, String, Properties, Properties, Integer, Boolean, long, TimeUnit) - * @see #triggerAdhocScript(String, String, Properties) - * @deprecated use {@link #runAdhocScript(RunAdhocScript)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution runAdhocScript(String project, String scriptFilename, Properties options) - throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, - IOException { - return runAdhocScript(project, scriptFilename, options, null); - } - - /** - * 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 not be dispatched to nodes, but be executed on the - * RunDeck server. - * - * @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 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 scriptFilename is blank (null, empty or whitespace) - * @throws IOException if we failed to read the file - * @see #runAdhocScript(String, String, Properties, Properties, Integer, Boolean, long, TimeUnit) - * @see #triggerAdhocScript(String, String, Properties) - * @deprecated use {@link #runAdhocScript(RunAdhocScript, long, java.util.concurrent.TimeUnit)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution runAdhocScript(String project, String scriptFilename, Properties options, - long poolingInterval, TimeUnit poolingUnit) throws RundeckApiException, RundeckApiLoginException, - RundeckApiTokenException, IllegalArgumentException, IOException { - return runAdhocScript(project, scriptFilename, options, 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 (every 5 seconds) 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 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 script will be executed. See {@link NodeFiltersBuilder} - * @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 scriptFilename is blank (null, empty or whitespace) - * @throws IOException if we failed to read the file - * @see #runAdhocScript(String, String, Properties, Properties, Integer, Boolean, long, TimeUnit) - * @see #triggerAdhocScript(String, String, Properties, Properties) - * @deprecated use {@link #runAdhocScript(RunAdhocScript)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution runAdhocScript(String project, String scriptFilename, Properties options, - Properties nodeFilters) throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, - IllegalArgumentException, IOException { - return runAdhocScript(project, scriptFilename, options, nodeFilters, null, null); - } - - /** - * 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 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 script will be executed. See {@link NodeFiltersBuilder} - * @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 scriptFilename is blank (null, empty or whitespace) - * @throws IOException if we failed to read the file - * @see #runAdhocScript(String, String, Properties, Properties, Integer, Boolean, long, TimeUnit) - * @see #triggerAdhocScript(String, String, Properties, Properties) - * @deprecated use {@link #runAdhocScript(RunAdhocScript, long, java.util.concurrent.TimeUnit)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution runAdhocScript(String project, String scriptFilename, Properties options, - Properties nodeFilters, long poolingInterval, TimeUnit poolingUnit) throws RundeckApiException, - RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, IOException { - return runAdhocScript(project, scriptFilename, options, nodeFilters, null, 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 (every 5 seconds) 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 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 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 - * @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 scriptFilename is blank (null, empty or whitespace) - * @throws IOException if we failed to read the file - * @see #runAdhocScript(String, String, Properties, Properties, Integer, Boolean, long, TimeUnit) - * @see #triggerAdhocScript(String, String, Properties, Properties, Integer, Boolean) - * @deprecated use {@link #runAdhocScript(RunAdhocScript)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution runAdhocScript(String project, String scriptFilename, Properties options, - Properties nodeFilters, Integer nodeThreadcount, Boolean nodeKeepgoing) throws RundeckApiException, - RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, IOException { - return runAdhocScript(project, - scriptFilename, - options, - nodeFilters, - nodeThreadcount, - nodeKeepgoing, - DEFAULT_POOLING_INTERVAL, - DEFAULT_POOLING_UNIT); - } - - /** - * 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 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 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 or scriptFilename is blank (null, empty or whitespace) - * @throws IOException if we failed to read the file - * @see #runAdhocScript(String, InputStream, Properties, Properties, Integer, Boolean, long, TimeUnit) - * @see #triggerAdhocScript(String, String, Properties, Properties, Integer, Boolean) - * - * @deprecated use {@link #runAdhocScript(RunAdhocScript, long, java.util.concurrent.TimeUnit)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution runAdhocScript(String project, String scriptFilename, Properties options, - Properties nodeFilters, Integer nodeThreadcount, Boolean nodeKeepgoing, long poolingInterval, - TimeUnit poolingUnit) throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, - IllegalArgumentException, IOException { - AssertUtil.notBlank(scriptFilename, "scriptFilename is mandatory to run an ad-hoc script !"); - FileInputStream stream = null; - try { - stream = FileUtils.openInputStream(new File(scriptFilename)); - return runAdhocScript(RunAdhocScriptBuilder.builder() - .setProject(project) - .setScript(stream) - .setNodeFilters(nodeFilters) - .setArgString(ParametersUtil.generateArgString(options)) - .setNodeThreadcount(nodeThreadcount) - .setNodeKeepgoing(nodeKeepgoing) - .build(), - poolingInterval, - poolingUnit); - } finally { - IOUtils.closeQuietly(stream); - } - } - - /** - * 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 (every 5 seconds) to know if the execution is finished (or aborted) or is still - * running. The script will not be dispatched to nodes, but be executed on the RunDeck server. - * - * @param project name of the project - mandatory - * @param script inputStream for reading the script to be executed - mandatory - * @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, InputStream, Properties, Properties, Integer, Boolean, long, TimeUnit) - * @see #triggerAdhocScript(String, InputStream) - * @deprecated use {@link #runAdhocScript(RunAdhocScript)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution runAdhocScript(String project, InputStream script) throws RundeckApiException, - RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, IOException { - return runAdhocScript(project, script, null); - } - - /** - * 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 not be dispatched to nodes, but be executed on the - * RunDeck server. - * - * @param project name of the project - mandatory - * @param script inputStream for reading the script to be executed - mandatory - * @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, InputStream, Properties, Properties, Integer, Boolean, long, TimeUnit) - * @see #triggerAdhocScript(String, InputStream) - * @deprecated use {@link #runAdhocScript(RunAdhocScript, long, java.util.concurrent.TimeUnit)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution runAdhocScript(String project, InputStream script, long poolingInterval, - TimeUnit poolingUnit) throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, - IllegalArgumentException, IOException { - return runAdhocScript(project, script, 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 (every 5 seconds) to know if the execution is finished (or aborted) or is still - * running. The script will not be dispatched to nodes, but be executed on the RunDeck server. - * - * @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}. - * @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, InputStream, Properties, Properties, Integer, Boolean, long, TimeUnit) - * @see #triggerAdhocScript(String, InputStream, Properties) - * @deprecated use {@link #runAdhocScript(RunAdhocScript)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution runAdhocScript(String project, InputStream script, Properties options) - throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, - IOException { - return runAdhocScript(project, script, options, null); - } - - /** - * 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 not be dispatched to nodes, but be executed on the - * RunDeck server. - * - * @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 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, InputStream, Properties, Properties, Integer, Boolean, long, TimeUnit) - * @see #triggerAdhocScript(String, InputStream, Properties) - * @deprecated use {@link #runAdhocScript(RunAdhocScript, long, java.util.concurrent.TimeUnit)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution runAdhocScript(String project, InputStream script, Properties options, - long poolingInterval, TimeUnit poolingUnit) throws RundeckApiException, RundeckApiLoginException, - RundeckApiTokenException, IllegalArgumentException, IOException { - return runAdhocScript(project, script, options, 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 (every 5 seconds) 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} - * @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, InputStream, Properties, Properties, Integer, Boolean, long, TimeUnit) - * @see #triggerAdhocScript(String, InputStream, Properties, Properties) - * @deprecated use {@link #runAdhocScript(RunAdhocScript)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution runAdhocScript(String project, InputStream script, Properties options, - Properties nodeFilters) throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, - IllegalArgumentException, IOException { - return runAdhocScript(project, script, options, nodeFilters, null, null); - } - - /** - * 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 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, InputStream, Properties, Properties, Integer, Boolean, long, TimeUnit) - * @see #triggerAdhocScript(String, InputStream, Properties, Properties) - * @deprecated use {@link #runAdhocScript(RunAdhocScript, long, java.util.concurrent.TimeUnit)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution runAdhocScript(String project, InputStream script, Properties options, - Properties nodeFilters, long poolingInterval, TimeUnit poolingUnit) throws RundeckApiException, - RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, IOException { - return runAdhocScript(project, script, options, nodeFilters, null, 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 (every 5 seconds) 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 - * @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, InputStream, Properties, Properties, Integer, Boolean, long, TimeUnit) - * @see #triggerAdhocScript(String, InputStream, Properties, Properties, Integer, Boolean) - * @deprecated use {@link #runAdhocScript(RunAdhocScript)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution runAdhocScript(String project, InputStream script, Properties options, - Properties nodeFilters, Integer nodeThreadcount, Boolean nodeKeepgoing) throws RundeckApiException, - RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, IOException { - return runAdhocScript(project, - script, - options, - nodeFilters, - nodeThreadcount, - nodeKeepgoing, - DEFAULT_POOLING_INTERVAL, - DEFAULT_POOLING_UNIT); - } /** * Run an ad-hoc script, and wait until its execution is finished (or aborted) to return. We will poll the RunDeck @@ -2510,80 +1033,6 @@ public class RundeckClient implements Serializable { DEFAULT_POOLING_UNIT); } - /** - * 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) - * @deprecated use {@link #runAdhocScript(RunAdhocScript, long, java.util.concurrent.TimeUnit)}, this method will be - * removed in version 10 of this library - */ - public RundeckExecution runAdhocScript(String project, InputStream script, Properties options, - 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) - * @deprecated use {@link #runAdhocScript(RunAdhocScript, long, java.util.concurrent.TimeUnit)}, this method will be - * removed in version 10 of this library - */ - 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 { - return runAdhocScript(RunAdhocScriptBuilder.builder() - .setProject(project) - .setScript(script) - .setNodeFilters(nodeFilters) - .setArgString(ParametersUtil.generateArgString(options)) - .setNodeThreadcount(nodeThreadcount) - .setNodeKeepgoing(nodeKeepgoing) - .setAsUser(asUser) - .build(), poolingInterval, poolingUnit); - } - /** * Run an ad-hoc script read from a file, 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 diff --git a/src/site/confluence/status.confluence b/src/site/confluence/status.confluence index 7b31a17..a665d74 100644 --- a/src/site/confluence/status.confluence +++ b/src/site/confluence/status.confluence @@ -92,3 +92,4 @@ h2. RunDeck API version 10 * Execution Output with State - Retrieve log output with state change information - OK * Execution Output - Retrieve log output for a particular node or step - OK * Execution Info - added successfulNodes and failedNodes detail. - OK +* Deprecation: Remove methods deprecated until version 10. - *TODO* diff --git a/src/test/java/org/rundeck/api/RundeckClientTest.java b/src/test/java/org/rundeck/api/RundeckClientTest.java index cfcea44..6e755db 100644 --- a/src/test/java/org/rundeck/api/RundeckClientTest.java +++ b/src/test/java/org/rundeck/api/RundeckClientTest.java @@ -364,22 +364,7 @@ public class RundeckClientTest { Assert.assertNull(delete.getMessage()); Assert.assertEquals("3a6d16be-4268-4d26-86a9-cebc1781f768", delete.getId()); } - @Test - @Betamax(tape = "trigger_job_basic") - public void triggerJobDeprecatedBasic() throws Exception { - RundeckClient client = createClient(TEST_TOKEN_3, 5); - 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_basic") public void triggerJobBasic() throws Exception { @@ -396,22 +381,7 @@ public class RundeckClientTest { Assert.assertEquals(RundeckExecution.ExecutionStatus.RUNNING, test.getStatus()); } - @Test - @Betamax(tape = "trigger_job_as_user") - public void triggerJobDeprecatedAsUser() throws Exception { - RundeckClient client = createClient(TEST_TOKEN_3, 5); - 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") public void triggerJobAsUser() throws Exception { @@ -431,19 +401,7 @@ public class RundeckClientTest { Assert.assertEquals(RundeckExecution.ExecutionStatus.RUNNING, test.getStatus()); } - @Test - @Betamax(tape = "trigger_job_as_user_unauthorized") - public void triggerJobDeprecatedAsUserUnauthorized() throws Exception { - RundeckClient client = createClient(TEST_TOKEN_3, 5); - 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_job_as_user_unauthorized") public void triggerJobAsUserUnauthorized() throws Exception { @@ -461,21 +419,7 @@ public class RundeckClientTest { } } - @Test - @Betamax(tape = "trigger_adhoc_command") - public void triggerAdhocCommandDeprecated() throws Exception { - RundeckClient client = createClient(TEST_TOKEN_3, 5); - 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") @@ -496,21 +440,7 @@ public class RundeckClientTest { Assert.assertEquals(RundeckExecution.ExecutionStatus.SUCCEEDED, test.getStatus()); } - @Test - @Betamax(tape = "trigger_adhoc_command_as_user") - public void triggerAdhocCommandDeprecatedAsUser() throws Exception { - RundeckClient client = createClient(TEST_TOKEN_3, 5); - 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") public void triggerAdhocCommandAsUser() throws Exception { @@ -532,19 +462,7 @@ public class RundeckClientTest { 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 triggerAdhocCommandDeprecatedAsUserUnauthorized() throws Exception { - RundeckClient client = createClient(TEST_TOKEN_3, 5); - 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_command_as_user_unauthorized") public void triggerAdhocCommandAsUserUnauthorized() throws Exception { @@ -565,24 +483,7 @@ public class RundeckClientTest { } } - @Test - @Betamax(tape = "trigger_adhoc_script") - public void triggerAdhocScriptDeprecated() throws Exception { - RundeckClient client = createClient(TEST_TOKEN_3, 5); - String script = "#!/bin/bash\n" + - "echo test trigger_adhoc_script\n"; - ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(script.getBytes()); - final RundeckExecution test - = client.triggerAdhocScript("test", byteArrayInputStream,(Properties) 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") public void triggerAdhocScript() throws Exception { @@ -602,24 +503,7 @@ public class RundeckClientTest { Assert.assertEquals("admin", test.getStartedBy()); Assert.assertEquals(RundeckExecution.ExecutionStatus.RUNNING, test.getStatus()); } - @Test - @Betamax(tape = "trigger_adhoc_script_as_user") - public void triggerAdhocScriptDeprecatedAsUser() throws Exception { - RundeckClient client = createClient(TEST_TOKEN_3, 5); - String script = "#!/bin/bash\n" + - "echo test trigger_adhoc_script\n"; - ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(script.getBytes()); - final RundeckExecution test - = client.triggerAdhocScript("test", byteArrayInputStream, (Properties) 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") public void triggerAdhocScriptAsUser() throws Exception { @@ -639,23 +523,7 @@ public class RundeckClientTest { 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 triggerAdhocScriptDeprecatedAsUserUnauthorized() throws Exception { - RundeckClient client = createClient(TEST_TOKEN_3, 5); - 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, (Properties) 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 = "trigger_adhoc_script_as_user_unauthorized") public void triggerAdhocScriptAsUserUnauthorized() throws Exception { From 7409d30d933809d502e4df9f0409257f7ada9713 Mon Sep 17 00:00:00 2001 From: Greg Schueler+ * There are three methods for authentication : login-based or token-based or session-based. + * Login authentication requires + * both a "login" and a "password". Token-based requires a "token" (also called "auth-token"). See the RunDeck * documentation for generating such a token.
+ *+ * Session-based authentication allows re-use of a previous login session. See {@link #testAuth()}. + *
+ *+ * Deprecation notice: All public constructors for this class are deprecated. Use the {@link RundeckClientBuilder} or {@link #builder()} convenience method to create a RundeckClient. The public constructors will be made non-public in version 12 of this library. + *
*
*
* // using login-based authentication :
- * RundeckClient rundeck = new RundeckClient("http://localhost:4440", "admin", "admin");
+ * RundeckClient rundeck = RundeckClient.builder()
+ * .url("http://localhost:4440")
+ * .login("admin", "admin").build();
* // or for a token-based authentication :
- * RundeckClient rundeck = new RundeckClient("http://localhost:4440", "PDDNKo5VE29kpk4prOUDr2rsKdRkEvsD");
+ * RundeckClient rundeck = RundeckClient.builder()
+ * .url("http://localhost:4440")
+ * .token("PDDNKo5VE29kpk4prOUDr2rsKdRkEvsD").build();
*
* List<RundeckProject> projects = rundeck.getProjects();
*
@@ -162,6 +174,9 @@ public class RundeckClient implements Serializable {
* @param login to use for authentication on the RunDeck instance
* @param password to use for authentication on the RunDeck instance
* @throws IllegalArgumentException if the url, login or password is blank (null, empty or whitespace)
+ *
+ * @deprecated Use the builder {@link RundeckClientBuilder} or {@link #builder()}, this method will not be public in version 12 of this
+ * library.
*/
public RundeckClient(String url, String login, String password) throws IllegalArgumentException {
this(url);
@@ -181,7 +196,7 @@ public class RundeckClient implements Serializable {
* @param sessionID to use for session authentication on the RunDeck instance
* @param useToken should be true if using token, false if using sessionID
* @throws IllegalArgumentException if the url or token is blank (null, empty or whitespace)
- * @deprecated Use the builder {@link RundeckClientBuilder}, this method will not be public in version 10 of this library.
+ * @deprecated Use the builder {@link RundeckClientBuilder} or {@link #builder()}, this method will not be public in version 10 of this library.
*/
private RundeckClient(String url, String token, String sessionID, boolean useToken) throws IllegalArgumentException {
this(url);
@@ -201,6 +216,16 @@ public class RundeckClient implements Serializable {
}
+ /**
+ * Instantiate a new {@link RundeckClient} for the RunDeck instance at the given url,
+ * using token-based authentication. Either token must be valid
+ * @param url of the RunDeck instance ("http://localhost:4440", "http://rundeck.your-compagny.com/", etc)
+ * @param token to use for authentication on the RunDeck instance
+ * @throws IllegalArgumentException if the url or token is blank (null, empty or whitespace)
+ * @deprecated Use the builder {@link RundeckClientBuilder} or {@link #builder()},
+ * this method will not be public in version 12 of this
+ * library.
+ */
public RundeckClient(String url, String token) throws IllegalArgumentException {
this(url, token, null, true);
}
@@ -1710,7 +1735,8 @@ public class RundeckClient implements Serializable {
* @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)
- * @deprecated renamed for clarity use {@link #getExecutionOutput(Long, int, int, long, int)}
+ * @deprecated renamed for clarity use {@link #getExecutionOutput(Long, int, int, long, int)}, will be removed in
+ * version 12 of this library
*/
public RundeckOutput getJobExecutionOutput(Long executionId, int offset, int lastlines, long lastmod, int maxlines)
throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
@@ -1909,7 +1935,8 @@ public class RundeckClient implements Serializable {
* @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)
- * @deprecated renamed for clarity use {@link #getExecutionOutput(Long, int, long, int)}
+ * @deprecated renamed for clarity use {@link #getExecutionOutput(Long, int, long, int)}, will be removed in
+ * version 12 of this library
*/
public RundeckOutput getJobExecutionOutput(Long executionId, int offset, long lastmod, int maxlines)
throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
From bf13167363477e059f2e5c52f6426db711008e6b Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Sat, 18 Jan 2014 11:28:06 -0800
Subject: [PATCH 27/89] Update project status
---
src/changes/changes.xml | 17 +++++++++++++++++
src/site/confluence/status.confluence | 2 +-
2 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 7a679ae..9263e66 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -22,6 +22,23 @@
Vincent Behar
+
+
+ Execution State - Retrieve workflow step and node state information
+
+
+ Execution Output with State - Retrieve log output with state change information
+
+
+ Execution Output - Retrieve log output for a particular node or step.
+
+
+ Execution Info - added successfulNodes and failedNodes detail.
+
+
+ Remove deprecated RundeckClient methods.
+
+
Issue #7: Fix authentication to Tomcat container (thanks @katanafleet)
diff --git a/src/site/confluence/status.confluence b/src/site/confluence/status.confluence
index a665d74..3a3d96b 100644
--- a/src/site/confluence/status.confluence
+++ b/src/site/confluence/status.confluence
@@ -92,4 +92,4 @@ h2. RunDeck API version 10
* Execution Output with State - Retrieve log output with state change information - OK
* Execution Output - Retrieve log output for a particular node or step - OK
* Execution Info - added successfulNodes and failedNodes detail. - OK
-* Deprecation: Remove methods deprecated until version 10. - *TODO*
+* Deprecation: Remove methods deprecated until version 10. - OK
From ec439560b5067244aebb77698d470634133d12b7 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Sat, 18 Jan 2014 11:28:59 -0800
Subject: [PATCH 28/89] Update version to 10.0-SNAPSHOT
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 501ebe6..abb0455 100644
--- a/pom.xml
+++ b/pom.xml
@@ -27,7 +27,7 @@
org.rundeck
rundeck-api-java-client
- 9.4-SNAPSHOT
+ 10.0-SNAPSHOT
jar
RunDeck API - Java Client
Java client for the RunDeck REST API
From 8a495f8723abd9da3418c55970e5401efebcfd00 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Thu, 27 Feb 2014 09:50:06 -0800
Subject: [PATCH 29/89] [maven-release-plugin] prepare release
rundeck-api-java-client-10.0
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index abb0455..585ffcd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -27,7 +27,7 @@
org.rundeck
rundeck-api-java-client
- 10.0-SNAPSHOT
+ 10.0
jar
RunDeck API - Java Client
Java client for the RunDeck REST API
From e95892e88eb98cf0c31acb0f66edd471955f2b81 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Thu, 27 Feb 2014 09:50:11 -0800
Subject: [PATCH 30/89] [maven-release-plugin] prepare for next development
iteration
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 585ffcd..d284be1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -27,7 +27,7 @@
org.rundeck
rundeck-api-java-client
- 10.0
+ 10.1-SNAPSHOT
jar
RunDeck API - Java Client
Java client for the RunDeck REST API
From 7aa512f1ac269f7f9cf7a618549b370f810d1c7c Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Thu, 17 Apr 2014 17:40:24 -0700
Subject: [PATCH 31/89] add .travis.yml
---
.travis.yml | 1 +
1 file changed, 1 insertion(+)
create mode 100644 .travis.yml
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..dff5f3a
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1 @@
+language: java
From 9ebd63e9536b1baa13a45a92d6d4991dc888f8cd Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Wed, 23 Apr 2014 16:22:02 -0700
Subject: [PATCH 32/89] Add 10.0 release date in changes
---
src/changes/changes.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 9263e66..ba52cb2 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -22,7 +22,7 @@
Vincent Behar
-
+
Execution State - Retrieve workflow step and node state information
From c3b1cbc39f510c917b1a63ff486e7adcb809db08 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Thu, 27 Feb 2014 12:29:37 -0800
Subject: [PATCH 33/89] PRoduces xml stream from a document
---
.../api/util/DocumentContentProducer.java | 38 +++++++++++++++++++
1 file changed, 38 insertions(+)
create mode 100644 src/main/java/org/rundeck/api/util/DocumentContentProducer.java
diff --git a/src/main/java/org/rundeck/api/util/DocumentContentProducer.java b/src/main/java/org/rundeck/api/util/DocumentContentProducer.java
new file mode 100644
index 0000000..ace7840
--- /dev/null
+++ b/src/main/java/org/rundeck/api/util/DocumentContentProducer.java
@@ -0,0 +1,38 @@
+package org.rundeck.api.util;
+
+import org.apache.http.entity.ContentProducer;
+import org.dom4j.Document;
+import org.dom4j.io.OutputFormat;
+import org.dom4j.io.XMLWriter;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * DocumentContentProducer writes XML document to a stream
+ *
+ * @author greg
+ * @since 2014-02-27
+ */
+public class DocumentContentProducer implements ContentProducer {
+ Document document;
+ private OutputFormat format;
+
+ public DocumentContentProducer(final Document document, final OutputFormat format) {
+ this.document = document;
+ this.format = format;
+ }
+
+ public DocumentContentProducer(final Document document) {
+ this.document = document;
+ format = new OutputFormat("", false, "UTF-8");
+ }
+
+ @Override
+ public void writeTo(final OutputStream outstream) throws IOException {
+
+ final XMLWriter xmlWriter = new XMLWriter(outstream, format);
+ xmlWriter.write(document);
+ xmlWriter.flush();
+ }
+}
From bd7e8f5cec2eb2f154818b6218d7d376e3c349d1 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Thu, 27 Feb 2014 12:30:07 -0800
Subject: [PATCH 34/89] Allow adding an xml document to the api request
---
.../java/org/rundeck/api/ApiPathBuilder.java | 20 ++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/src/main/java/org/rundeck/api/ApiPathBuilder.java b/src/main/java/org/rundeck/api/ApiPathBuilder.java
index 22643c8..e749004 100644
--- a/src/main/java/org/rundeck/api/ApiPathBuilder.java
+++ b/src/main/java/org/rundeck/api/ApiPathBuilder.java
@@ -26,6 +26,7 @@ import java.util.Properties;
import org.apache.commons.lang.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
+import org.dom4j.Document;
import org.rundeck.api.util.ParametersUtil;
/**
@@ -43,6 +44,7 @@ class ApiPathBuilder {
/** When POSTing, we can add attachments */
private final Map attachments;
private final List form = new ArrayList();
+ private Document xmlDocument;
/** Marker for using the right separator between parameters ("?" or "&") */
private boolean firstParamDone = false;
@@ -266,6 +268,18 @@ class ApiPathBuilder {
}
return this;
}
+ /**
+ * When POSTing a request, add the given XMl Document as the content of the request.
+ *
+ * @param document XMl document to send
+ * @return this, for method chaining
+ */
+ public ApiPathBuilder xml(final Document document) {
+ if (document != null) {
+ xmlDocument = document;
+ }
+ return this;
+ }
/**
* @return all attachments to be POSTed, with their names
@@ -311,7 +325,7 @@ class ApiPathBuilder {
* Return true if there are any Attachments or Form data for a POST request.
*/
public boolean hasPostContent() {
- return getAttachments().size() > 0 || getForm().size() > 0;
+ return getAttachments().size() > 0 || getForm().size() > 0 || null != xmlDocument;
}
/**
@@ -321,6 +335,10 @@ class ApiPathBuilder {
return accept;
}
+ public Document getXmlDocument() {
+ return xmlDocument;
+ }
+
/**
* BuildsParameters can add URL or POST parameters to an {@link ApiPathBuilder}
*
From 7543d5d630eb51acd1e05b215bb187d3f5f23fa7 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Thu, 27 Feb 2014 12:30:23 -0800
Subject: [PATCH 35/89] Send xml document if included in request
---
src/main/java/org/rundeck/api/ApiCall.java | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/main/java/org/rundeck/api/ApiCall.java b/src/main/java/org/rundeck/api/ApiCall.java
index daac945..1dc2059 100644
--- a/src/main/java/org/rundeck/api/ApiCall.java
+++ b/src/main/java/org/rundeck/api/ApiCall.java
@@ -32,6 +32,7 @@ import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
+import org.apache.http.entity.EntityTemplate;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.InputStreamBody;
@@ -48,6 +49,7 @@ import org.rundeck.api.RundeckApiException.RundeckApiTokenException;
import org.rundeck.api.parser.ParserHelper;
import org.rundeck.api.parser.XmlNodeParser;
import org.rundeck.api.util.AssertUtil;
+import org.rundeck.api.util.DocumentContentProducer;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -286,6 +288,9 @@ class ApiCall {
} catch (UnsupportedEncodingException e) {
throw new RundeckApiException("Unsupported encoding: " + e.getMessage(), e);
}
+ }else if(apiPath.getXmlDocument()!=null) {
+ httpPost.setHeader("Content-Type", "application/xml");
+ httpPost.setEntity(new EntityTemplate(new DocumentContentProducer(apiPath.getXmlDocument())));
}else {
throw new IllegalArgumentException("No Form or Multipart entity for POST content-body");
}
From 303a3dec576f5c390855a95435d1b5b635856a7d Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Thu, 27 Feb 2014 12:31:09 -0800
Subject: [PATCH 36/89] Generates project xml document for creation request
---
.../api/generator/ProjectGenerator.java | 38 +++++++++++++++++++
.../api/generator/ProjectGeneratorTest.java | 25 ++++++++++++
2 files changed, 63 insertions(+)
create mode 100644 src/main/java/org/rundeck/api/generator/ProjectGenerator.java
create mode 100644 src/test/java/org/rundeck/api/generator/ProjectGeneratorTest.java
diff --git a/src/main/java/org/rundeck/api/generator/ProjectGenerator.java b/src/main/java/org/rundeck/api/generator/ProjectGenerator.java
new file mode 100644
index 0000000..37a45a4
--- /dev/null
+++ b/src/main/java/org/rundeck/api/generator/ProjectGenerator.java
@@ -0,0 +1,38 @@
+package org.rundeck.api.generator;
+
+import org.dom4j.Document;
+import org.dom4j.DocumentFactory;
+import org.dom4j.Element;
+import org.rundeck.api.domain.ProjectConfig;
+import org.rundeck.api.domain.RundeckProject;
+
+/**
+ * ProjectGenerator is ...
+ *
+ * @author greg
+ * @since 2014-02-27
+ */
+public class ProjectGenerator {
+ RundeckProject project;
+
+ public ProjectGenerator(RundeckProject project) {
+ this.project = project;
+ }
+
+ public Document generate() {
+ Document projectDom = DocumentFactory.getInstance().createDocument();
+ Element rootElem = projectDom.addElement("project");
+ rootElem.addElement("name").setText(project.getName());
+ ProjectConfig configuration = project.getProjectConfig();
+ if (null != configuration) {
+
+ Element config = rootElem.addElement("config");
+ for (String s : configuration.getProperties().keySet()) {
+ Element property = config.addElement("property");
+ property.addAttribute("key", s);
+ property.addAttribute("value", configuration.getProperties().get(s));
+ }
+ }
+ return projectDom;
+ }
+}
diff --git a/src/test/java/org/rundeck/api/generator/ProjectGeneratorTest.java b/src/test/java/org/rundeck/api/generator/ProjectGeneratorTest.java
new file mode 100644
index 0000000..a9c5b1b
--- /dev/null
+++ b/src/test/java/org/rundeck/api/generator/ProjectGeneratorTest.java
@@ -0,0 +1,25 @@
+package org.rundeck.api.generator;
+
+import junit.framework.Assert;
+import org.dom4j.Document;
+import org.junit.Test;
+import org.rundeck.api.domain.RundeckProject;
+
+/**
+ * ProjectGeneratorTest is ...
+ *
+ * @author greg
+ * @since 2014-02-27
+ */
+public class ProjectGeneratorTest {
+ @Test
+ public void generate() {
+ RundeckProject project = new RundeckProject();
+ project.setName("monkey1");
+
+ Document doc = new ProjectGenerator(project).generate();
+ Assert.assertEquals("project", doc.getRootElement().getName());
+ Assert.assertNotNull(doc.selectSingleNode("/project/name"));
+ Assert.assertEquals("monkey1", doc.selectSingleNode("/project/name").getText());
+ }
+}
From b571c2a5beb1ca07bf7e12db7ad549777bf98d8b Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Thu, 27 Feb 2014 12:31:42 -0800
Subject: [PATCH 37/89] Support API v11, and project create endpoint
---
.../java/org/rundeck/api/RundeckClient.java | 118 +++++++++++++-----
.../org/rundeck/api/domain/ProjectConfig.java | 64 ++++++++++
.../rundeck/api/domain/RundeckProject.java | 23 +++-
.../api/parser/ProjectConfigParser.java | 43 +++++++
.../org/rundeck/api/parser/ProjectParser.java | 5 +-
.../rundeck/api/parser/ProjectParserV11.java | 36 ++++++
.../org/rundeck/api/RundeckClientTest.java | 10 ++
.../api/parser/ProjectConfigParserTest.java | 51 ++++++++
.../api/parser/ProjectParserV11Test.java | 28 +++++
.../betamax/tapes/create_projectv11.yaml | 26 ++++
.../org/rundeck/api/parser/projectv11.xml | 17 +++
11 files changed, 388 insertions(+), 33 deletions(-)
create mode 100644 src/main/java/org/rundeck/api/domain/ProjectConfig.java
create mode 100644 src/main/java/org/rundeck/api/parser/ProjectConfigParser.java
create mode 100644 src/main/java/org/rundeck/api/parser/ProjectParserV11.java
create mode 100644 src/test/java/org/rundeck/api/parser/ProjectConfigParserTest.java
create mode 100644 src/test/java/org/rundeck/api/parser/ProjectParserV11Test.java
create mode 100644 src/test/resources/betamax/tapes/create_projectv11.yaml
create mode 100644 src/test/resources/org/rundeck/api/parser/projectv11.xml
diff --git a/src/main/java/org/rundeck/api/RundeckClient.java b/src/main/java/org/rundeck/api/RundeckClient.java
index 61911bc..57ae3af 100644
--- a/src/main/java/org/rundeck/api/RundeckClient.java
+++ b/src/main/java/org/rundeck/api/RundeckClient.java
@@ -18,10 +18,14 @@ package org.rundeck.api;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
+import org.dom4j.Document;
+import org.dom4j.DocumentFactory;
+import org.dom4j.Element;
import org.rundeck.api.RundeckApiException.RundeckApiLoginException;
import org.rundeck.api.RundeckApiException.RundeckApiTokenException;
import org.rundeck.api.domain.*;
import org.rundeck.api.domain.RundeckExecution.ExecutionStatus;
+import org.rundeck.api.generator.ProjectGenerator;
import org.rundeck.api.parser.*;
import org.rundeck.api.query.ExecutionQuery;
import org.rundeck.api.util.AssertUtil;
@@ -33,10 +37,7 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Properties;
+import java.util.*;
import java.util.concurrent.TimeUnit;
/**
@@ -95,6 +96,7 @@ public class RundeckClient implements Serializable {
V8(8),
V9(9),
V10(10),
+ V11(11),
;
private int versionNumber;
@@ -108,7 +110,7 @@ public class RundeckClient implements Serializable {
}
}
/** Version of the API supported */
- public static final transient int API_VERSION = Version.V10.getVersionNumber();
+ public static final transient int API_VERSION = Version.V11.getVersionNumber();
private static final String API = "/api/";
@@ -274,10 +276,26 @@ public class RundeckClient implements Serializable {
testAuth();
}
+ /**
+ * Return root xpath for xml api results. for v11 and later it is empty, for earlier it is "result"
+ *
+ * @return
+ */
+ private String rootXpath() {
+ return getApiVersion() < Version.V11.getVersionNumber() ? "result" : "";
+ }
/*
* Projects
*/
+ private ProjectParser createProjectParser() {
+ return createProjectParser(null);
+ }
+
+ private ProjectParser createProjectParser(final String xpath) {
+ return new ProjectParserV11(xpath);
+ }
+
/**
* List all projects
*
@@ -289,7 +307,8 @@ public class RundeckClient implements Serializable {
public List getProjects() throws RundeckApiException, RundeckApiLoginException,
RundeckApiTokenException {
return new ApiCall(this).get(new ApiPathBuilder("/projects"),
- new ListParser(new ProjectParser(), "result/projects/project"));
+ new ListParser(createProjectParser(), rootXpath() +
+ "/projects/project"));
}
/**
@@ -306,7 +325,48 @@ public class RundeckClient implements Serializable {
RundeckApiTokenException, IllegalArgumentException {
AssertUtil.notBlank(projectName, "projectName is mandatory to get the details of a project !");
return new ApiCall(this).get(new ApiPathBuilder("/project/", projectName),
- new ProjectParser("result/projects/project"));
+ createProjectParser(rootXpath() +
+ (getApiVersion() < Version.V11.getVersionNumber()
+ ? "/projects/project"
+ : "/project"
+ )));
+ }
+
+ /**
+ * Create a new project, and return the new definition
+ *
+ * @param projectName name of the project - mandatory
+ * @param configuration project configuration properties
+ *
+ * @return a {@link RundeckProject} instance - 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 projectName is blank (null, empty or whitespace)
+ */
+ public RundeckProject createProject(String projectName, Map configuration) throws
+ RundeckApiException, RundeckApiLoginException,
+ RundeckApiTokenException, IllegalArgumentException {
+
+ AssertUtil.notBlank(projectName, "projectName is mandatory to get the details of a project !");
+ return new ApiCall(this)
+ .post(new ApiPathBuilder("/projects").xml(
+ projectDocument(projectName, configuration)
+ ), createProjectParser(rootXpath() +
+ (getApiVersion() < Version.V11.getVersionNumber()
+ ? "/projects/project"
+ : "/project"
+ )));
+ }
+
+ private Document projectDocument(String projectName, Map configuration) {
+ RundeckProject project = new RundeckProject();
+ project.setName(projectName);
+ if (null != configuration) {
+ project.setProjectConfig(new ProjectConfig(configuration));
+ }
+ return new ProjectGenerator(project).generate();
}
/*
@@ -366,7 +426,7 @@ public class RundeckClient implements Serializable {
.param("jobFilter", jobFilter)
.param("groupPath", groupPath)
.param("idlist", StringUtils.join(jobIds, ",")),
- new ListParser(new JobParser(), "result/jobs/job"));
+ new ListParser(new JobParser(), rootXpath()+"/jobs/job"));
}
/**
@@ -699,7 +759,7 @@ public class RundeckClient implements Serializable {
//API v8
request.param("project", rundeckJobsImport.getProject());
}
- return new ApiCall(this).post(request, new JobsImportResultParser("result"));
+ return new ApiCall(this).post(request, new JobsImportResultParser(rootXpath()));
}
/**
@@ -755,7 +815,7 @@ public class RundeckClient implements Serializable {
public String deleteJob(String jobId) throws RundeckApiException, RundeckApiLoginException,
RundeckApiTokenException, IllegalArgumentException {
AssertUtil.notBlank(jobId, "jobId is mandatory to delete a job !");
- return new ApiCall(this).delete(new ApiPathBuilder("/job/", jobId), new StringParser("result/success/message"));
+ return new ApiCall(this).delete(new ApiPathBuilder("/job/", jobId), new StringParser(rootXpath()+"/success/message"));
}
/**
* Delete multiple jobs, identified by the given IDs
@@ -773,7 +833,7 @@ public class RundeckClient implements Serializable {
throw new IllegalArgumentException("jobIds are mandatory to delete a job");
}
return new ApiCall(this).post(new ApiPathBuilder("/jobs/delete").field("ids",jobIds),
- new BulkDeleteParser("result/deleteJobs"));
+ new BulkDeleteParser(rootXpath()+"/deleteJobs"));
}
/**
@@ -798,7 +858,7 @@ public class RundeckClient implements Serializable {
if(null!=jobRun.getAsUser()) {
apiPath.param("asUser", jobRun.getAsUser());
}
- return new ApiCall(this).get(apiPath, new ExecutionParser("result/executions/execution"));
+ return new ApiCall(this).get(apiPath, new ExecutionParser(rootXpath()+"/executions/execution"));
}
@@ -896,7 +956,7 @@ public class RundeckClient implements Serializable {
if(null!= command.getAsUser()) {
apiPath.param("asUser", command.getAsUser());
}
- RundeckExecution execution = new ApiCall(this).get(apiPath, new ExecutionParser("result/execution"));
+ RundeckExecution execution = new ApiCall(this).get(apiPath, new ExecutionParser(rootXpath()+"/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());
}
@@ -1030,7 +1090,7 @@ public class RundeckClient implements Serializable {
if(null!=script.getAsUser()) {
apiPath.param("asUser", script.getAsUser());
}
- RundeckExecution execution = new ApiCall(this).post(apiPath, new ExecutionParser("result/execution"));
+ RundeckExecution execution = new ApiCall(this).post(apiPath, new ExecutionParser(rootXpath()+"/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());
}
@@ -1177,7 +1237,7 @@ public class RundeckClient implements Serializable {
AssertUtil.notBlank(project, "project is mandatory get all running executions !");
return new ApiCall(this).get(new ApiPathBuilder("/executions/running").param("project", project),
new ListParser(new ExecutionParser(),
- "result/executions/execution"));
+ rootXpath()+"/executions/execution"));
}
/**
@@ -1275,7 +1335,7 @@ public class RundeckClient implements Serializable {
.param("max", max)
.param("offset", offset),
new ListParser(new ExecutionParser(),
- "result/executions/execution"));
+ rootXpath()+"/executions/execution"));
}
/**
@@ -1302,7 +1362,7 @@ public class RundeckClient implements Serializable {
.param("offset", offset),
new PagedResultParser(
new ListParser(new ExecutionParser(), "execution"),
- "result/executions"
+ rootXpath()+"/executions"
)
);
}
@@ -1321,7 +1381,7 @@ public class RundeckClient implements Serializable {
RundeckApiTokenException, IllegalArgumentException {
AssertUtil.notNull(executionId, "executionId is mandatory to get the details of an execution !");
return new ApiCall(this).get(new ApiPathBuilder("/execution/", executionId.toString()),
- new ExecutionParser("result/executions/execution"));
+ new ExecutionParser(rootXpath()+"/executions/execution"));
}
/**
@@ -1356,7 +1416,7 @@ public class RundeckClient implements Serializable {
if(null!=asUser) {
apiPath.param("asUser", asUser);
}
- return new ApiCall(this).get(apiPath, new AbortParser("result/abort"));
+ return new ApiCall(this).get(apiPath, new AbortParser(rootXpath()+"/abort"));
}
/*
@@ -1548,7 +1608,7 @@ public class RundeckClient implements Serializable {
.param("end", end)
.param("max", max)
.param("offset", offset),
- new HistoryParser("result/events"));
+ new HistoryParser(rootXpath()+"/events"));
}
/**
@@ -1595,7 +1655,7 @@ public class RundeckClient implements Serializable {
.param("max", max)
.param("offset", offset);
- return new ApiCall(this).postOrGet(builder, new HistoryParser("result/events"));
+ return new ApiCall(this).postOrGet(builder, new HistoryParser(rootXpath()+"/events"));
}
/*
@@ -1773,7 +1833,7 @@ public class RundeckClient implements Serializable {
param.param("maxlines", maxlines);
}
return new ApiCall(this).get(param,
- new OutputParser("result/output", createOutputEntryParser()));
+ new OutputParser(rootXpath()+"/output", createOutputEntryParser()));
}
/**
* Get the execution state of the given execution
@@ -1792,7 +1852,7 @@ public class RundeckClient implements Serializable {
"/execution/", executionId.toString(),
"/state");
- return new ApiCall(this).get(param, new ExecutionStateParser("result/executionState"));
+ return new ApiCall(this).get(param, new ExecutionStateParser(rootXpath()+"/executionState"));
}
/**
@@ -1834,7 +1894,7 @@ public class RundeckClient implements Serializable {
param.param("maxlines", maxlines);
}
return new ApiCall(this).get(param,
- new OutputParser("result/output", createOutputEntryParser()));
+ new OutputParser(rootXpath()+"/output", createOutputEntryParser()));
}
/**
* Get the execution output of the given execution for the specified step
@@ -1875,7 +1935,7 @@ public class RundeckClient implements Serializable {
param.param("maxlines", maxlines);
}
return new ApiCall(this).get(param,
- new OutputParser("result/output", createOutputEntryParser()));
+ new OutputParser(rootXpath()+"/output", createOutputEntryParser()));
}
/**
* Get the execution output of the given execution for the specified step
@@ -1919,7 +1979,7 @@ public class RundeckClient implements Serializable {
param.param("maxlines", maxlines);
}
return new ApiCall(this).get(param,
- new OutputParser("result/output", createOutputEntryParser()));
+ new OutputParser(rootXpath()+"/output", createOutputEntryParser()));
}
@@ -1966,7 +2026,7 @@ public class RundeckClient implements Serializable {
if (maxlines > 0) {
param.param("maxlines", maxlines);
}
- return new ApiCall(this).get(param, new OutputParser("result/output", createOutputEntryParser()));
+ return new ApiCall(this).get(param, new OutputParser(rootXpath()+"/output", createOutputEntryParser()));
}
/**
* Get the execution state output sequence of the given job
@@ -1997,7 +2057,7 @@ public class RundeckClient implements Serializable {
if(stateOnly) {
param.param("stateOnly", true);
}
- return new ApiCall(this).get(param, new OutputParser("result/output", createOutputEntryParser()));
+ return new ApiCall(this).get(param, new OutputParser(rootXpath()+"/output", createOutputEntryParser()));
}
private OutputEntryParser createOutputEntryParser() {
@@ -2023,7 +2083,7 @@ public class RundeckClient implements Serializable {
*/
public RundeckSystemInfo getSystemInfo() throws RundeckApiException, RundeckApiLoginException,
RundeckApiTokenException {
- return new ApiCall(this).get(new ApiPathBuilder("/system/info"), new SystemInfoParser("result/system"));
+ return new ApiCall(this).get(new ApiPathBuilder("/system/info"), new SystemInfoParser(rootXpath()+"/system"));
}
/**
diff --git a/src/main/java/org/rundeck/api/domain/ProjectConfig.java b/src/main/java/org/rundeck/api/domain/ProjectConfig.java
new file mode 100644
index 0000000..ca3548f
--- /dev/null
+++ b/src/main/java/org/rundeck/api/domain/ProjectConfig.java
@@ -0,0 +1,64 @@
+package org.rundeck.api.domain;
+
+import java.io.Serializable;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * ProjectConfig is ...
+ *
+ * @author greg
+ * @since 2014-02-27
+ */
+public class ProjectConfig implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+ private LinkedHashMap properties = new LinkedHashMap();
+
+ public ProjectConfig() {
+ }
+
+ public ProjectConfig(Map properties) {
+ setProperties(properties);
+ }
+
+ public void setProperty(final String key, final String value) {
+ getProperties().put(key, value);
+ }
+
+ public void addProperties(final Map values) {
+ getProperties().putAll(values);
+ }
+
+ public Map getProperties() {
+ return properties;
+ }
+
+ public void setProperties(final Map properties) {
+ this.properties = new LinkedHashMap(properties);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof ProjectConfig)) return false;
+
+ ProjectConfig that = (ProjectConfig) o;
+
+ if (properties != null ? !properties.equals(that.properties) : that.properties != null) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return properties != null ? properties.hashCode() : 0;
+ }
+
+ @Override
+ public String toString() {
+ return "ProjectConfig{" +
+ "properties=" + properties +
+ '}';
+ }
+}
diff --git a/src/main/java/org/rundeck/api/domain/RundeckProject.java b/src/main/java/org/rundeck/api/domain/RundeckProject.java
index c5e3fa4..32e38ea 100644
--- a/src/main/java/org/rundeck/api/domain/RundeckProject.java
+++ b/src/main/java/org/rundeck/api/domain/RundeckProject.java
@@ -32,6 +32,8 @@ public class RundeckProject implements Serializable {
private String resourceModelProviderUrl;
+ private ProjectConfig projectConfig;
+
public String getName() {
return name;
}
@@ -56,10 +58,20 @@ public class RundeckProject implements Serializable {
this.resourceModelProviderUrl = resourceModelProviderUrl;
}
+ public ProjectConfig getProjectConfig() {
+ return projectConfig;
+ }
+
+ public void setProjectConfig(ProjectConfig projectConfig) {
+ this.projectConfig = projectConfig;
+ }
+
@Override
public String toString() {
- return "RundeckProject [name=" + name + ", description=" + description + ", resourceModelProviderUrl="
- + resourceModelProviderUrl + "]";
+ return "RundeckProject [name=" + name + ", description=" + description
+ + (null!=resourceModelProviderUrl? ", resourceModelProviderUrl=" + resourceModelProviderUrl : "")
+ + ", config="
+ + projectConfig + "]";
}
@Override
@@ -69,6 +81,7 @@ public class RundeckProject implements Serializable {
result = prime * result + ((description == null) ? 0 : description.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((resourceModelProviderUrl == null) ? 0 : resourceModelProviderUrl.hashCode());
+ result = prime * result + ((projectConfig == null) ? 0 : projectConfig.hashCode());
return result;
}
@@ -96,7 +109,11 @@ public class RundeckProject implements Serializable {
return false;
} else if (!resourceModelProviderUrl.equals(other.resourceModelProviderUrl))
return false;
+ if (projectConfig == null) {
+ if (other.projectConfig != null)
+ return false;
+ } else if (!projectConfig.equals(other.projectConfig))
+ return false;
return true;
}
-
}
diff --git a/src/main/java/org/rundeck/api/parser/ProjectConfigParser.java b/src/main/java/org/rundeck/api/parser/ProjectConfigParser.java
new file mode 100644
index 0000000..7e92ffe
--- /dev/null
+++ b/src/main/java/org/rundeck/api/parser/ProjectConfigParser.java
@@ -0,0 +1,43 @@
+package org.rundeck.api.parser;
+
+import org.dom4j.Node;
+import org.rundeck.api.domain.ProjectConfig;
+
+import java.util.List;
+
+/**
+ * ProjectConfigParser parses project "config" element contents
+ *
+ * @author greg
+ * @since 2014-02-27
+ */
+public class ProjectConfigParser implements XmlNodeParser {
+ private String xpath;
+
+ public ProjectConfigParser() {
+ }
+
+ public ProjectConfigParser(String xpath) {
+ this.xpath = xpath;
+ }
+
+ @Override
+ public ProjectConfig parseXmlNode(Node node) {
+ Node config1 = getXpath() != null ? node.selectSingleNode(getXpath()) : node;
+ ProjectConfig config = new ProjectConfig();
+ List property = config1.selectNodes("property");
+ for (Object o : property) {
+ Node propnode = (Node) o;
+ String key = propnode.valueOf("@key");
+ String value = propnode.valueOf("@value");
+ if (null != key && null != value) {
+ config.setProperty(key, value);
+ }
+ }
+ return config;
+ }
+
+ public String getXpath() {
+ return xpath;
+ }
+}
diff --git a/src/main/java/org/rundeck/api/parser/ProjectParser.java b/src/main/java/org/rundeck/api/parser/ProjectParser.java
index 999ec70..ef6ca13 100644
--- a/src/main/java/org/rundeck/api/parser/ProjectParser.java
+++ b/src/main/java/org/rundeck/api/parser/ProjectParser.java
@@ -42,7 +42,7 @@ public class ProjectParser implements XmlNodeParser {
@Override
public RundeckProject parseXmlNode(Node node) {
- Node projectNode = xpath != null ? node.selectSingleNode(xpath) : node;
+ Node projectNode = getXpath() != null ? node.selectSingleNode(getXpath()) : node;
RundeckProject project = new RundeckProject();
@@ -53,4 +53,7 @@ public class ProjectParser implements XmlNodeParser {
return project;
}
+ protected String getXpath() {
+ return xpath;
+ }
}
diff --git a/src/main/java/org/rundeck/api/parser/ProjectParserV11.java b/src/main/java/org/rundeck/api/parser/ProjectParserV11.java
new file mode 100644
index 0000000..631d941
--- /dev/null
+++ b/src/main/java/org/rundeck/api/parser/ProjectParserV11.java
@@ -0,0 +1,36 @@
+package org.rundeck.api.parser;
+
+import org.dom4j.Node;
+import org.rundeck.api.domain.ProjectConfig;
+import org.rundeck.api.domain.RundeckProject;
+
+import java.util.List;
+
+/**
+ * ProjectParserV11 supports embedded "config" element.
+ *
+ * @author greg
+ * @since 2014-02-27
+ */
+public class ProjectParserV11 extends ProjectParser {
+ public ProjectParserV11() {
+ }
+
+ public ProjectParserV11(final String xpath) {
+ super(xpath);
+ }
+
+ @Override
+ public RundeckProject parseXmlNode(final Node node) {
+ final RundeckProject rundeckProject = super.parseXmlNode(node);
+ final Node projectNode = getXpath() != null ? node.selectSingleNode(getXpath()) : node;
+ final Node config1 = projectNode.selectSingleNode("config");
+ if (config1 == null) {
+ return rundeckProject;
+ }
+
+ rundeckProject.setProjectConfig(new ProjectConfigParser().parseXmlNode(config1));
+
+ return rundeckProject;
+ }
+}
diff --git a/src/test/java/org/rundeck/api/RundeckClientTest.java b/src/test/java/org/rundeck/api/RundeckClientTest.java
index 6e755db..c66ea7c 100644
--- a/src/test/java/org/rundeck/api/RundeckClientTest.java
+++ b/src/test/java/org/rundeck/api/RundeckClientTest.java
@@ -82,6 +82,16 @@ public class RundeckClientTest {
Assert.assertNull(projects.get(0).getDescription());
}
@Test
+ @Betamax(tape = "create_projectv11")
+ public void createProject() throws Exception {
+
+ RundeckProject project = createClient(TEST_TOKEN_6,11).createProject("monkey1", null);
+ Assert.assertEquals("monkey1", project.getName());
+ Assert.assertEquals(null, project.getDescription());
+ Assert.assertNotNull(project.getProjectConfig());
+
+ }
+ @Test
@Betamax(tape = "get_history")
public void getHistory() throws Exception {
final RundeckHistory test = client.getHistory("test");
diff --git a/src/test/java/org/rundeck/api/parser/ProjectConfigParserTest.java b/src/test/java/org/rundeck/api/parser/ProjectConfigParserTest.java
new file mode 100644
index 0000000..cee0f6f
--- /dev/null
+++ b/src/test/java/org/rundeck/api/parser/ProjectConfigParserTest.java
@@ -0,0 +1,51 @@
+package org.rundeck.api.parser;
+
+import org.dom4j.Document;
+import org.junit.Assert;
+import org.junit.Test;
+import org.rundeck.api.domain.ProjectConfig;
+import org.rundeck.api.domain.RundeckProject;
+
+import java.io.InputStream;
+
+/**
+ * ProjectConfigParserTest is ...
+ *
+ * @author greg
+ * @since 2014-02-27
+ */
+public class ProjectConfigParserTest {
+ @Test
+ public void parseProject() throws Exception {
+ InputStream input = getClass().getResourceAsStream("projectv11.xml");
+ Document document = ParserHelper.loadDocument(input);
+
+ ProjectConfig config = new ProjectConfigParser("project/config").parseXmlNode(document);
+
+ Assert.assertEquals(10, config.getProperties().size());
+ Assert.assertEquals("ziggy", config.getProperties().get("project.name"));
+ Assert.assertEquals("false", config.getProperties().get("resources.source.1.config.requireFileExists"));
+ Assert.assertEquals("privateKey", config.getProperties().get("project.ssh-authentication"));
+ Assert.assertEquals("jsch-ssh", config.getProperties().get("service.NodeExecutor.default.provider"));
+ Assert.assertEquals("false", config.getProperties().get("resources.source.1.config.includeServerNode"));
+ Assert.assertEquals("false", config.getProperties().get("resources.source.1.config.generateFileAutomatically"));
+ Assert.assertEquals("/var/rundeck/projects/${project.name}/etc/resources.xml",
+ config.getProperties().get("resources.source.1.config.file"));
+ Assert.assertEquals("/var/lib/rundeck/.ssh/id_rsa", config.getProperties().get("project.ssh-keypath"));
+ Assert.assertEquals("jsch-scp", config.getProperties().get("service.FileCopier.default.provider"));
+ Assert.assertEquals("file", config.getProperties().get("resources.source.1.type"));
+ /*
+
+
+
+
+
+
+
+
+
+
+ */
+ }
+}
diff --git a/src/test/java/org/rundeck/api/parser/ProjectParserV11Test.java b/src/test/java/org/rundeck/api/parser/ProjectParserV11Test.java
new file mode 100644
index 0000000..cff9fc9
--- /dev/null
+++ b/src/test/java/org/rundeck/api/parser/ProjectParserV11Test.java
@@ -0,0 +1,28 @@
+package org.rundeck.api.parser;
+
+import org.dom4j.Document;
+import org.junit.Assert;
+import org.junit.Test;
+import org.rundeck.api.domain.RundeckProject;
+
+import java.io.InputStream;
+
+/**
+ * ProjectParserV11Test is ...
+ *
+ * @author greg
+ * @since 2014-02-27
+ */
+public class ProjectParserV11Test {
+ @Test
+ public void parseProject() throws Exception {
+ InputStream input = getClass().getResourceAsStream("projectv11.xml");
+ Document document = ParserHelper.loadDocument(input);
+
+ RundeckProject project = new ProjectParserV11("project").parseXmlNode(document);
+
+ Assert.assertEquals("ziggy", project.getName());
+ Assert.assertNull(project.getDescription());
+ Assert.assertNotNull(project.getProjectConfig());
+ }
+}
diff --git a/src/test/resources/betamax/tapes/create_projectv11.yaml b/src/test/resources/betamax/tapes/create_projectv11.yaml
new file mode 100644
index 0000000..e928798
--- /dev/null
+++ b/src/test/resources/betamax/tapes/create_projectv11.yaml
@@ -0,0 +1,26 @@
+!tape
+name: create_projectv11
+interactions:
+- recorded: 2014-02-27T19:45:35.430Z
+ request:
+ method: POST
+ uri: http://rundeck.local:4440/api/11/projects
+ headers:
+ Accept: text/xml
+ Content-Type: application/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ Transfer-Encoding: chunked
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: Do4d3NUD5DKk21DR4sNK755RcPk618vn
+ response:
+ status: 200
+ headers:
+ Content-Type: application/xml;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=1h2r5l35j4ynqo19dsm6xa2gv;Path=/
+ X-Rundeck-API-Version: '11'
+ X-Rundeck-API-XML-Response-Wrapper: 'false'
+ body: !!binary |-
+ PHByb2plY3QgdXJsPSdodHRwOi8vZGlnbmFuLmxvY2FsOjQ0NDAvYXBpLzExL3Byb2plY3QvbW9ua2V5MSc+CiAgPG5hbWU+bW9ua2V5MTwvbmFtZT4KICA8ZGVzY3JpcHRpb24+PC9kZXNjcmlwdGlvbj4KICA8Y29uZmlnPgogICAgPHByb3BlcnR5IGtleT0ncHJvamVjdC5uYW1lJyB2YWx1ZT0nbW9ua2V5MScgLz4KICAgIDxwcm9wZXJ0eSBrZXk9J3Byb2plY3Quc3NoLWF1dGhlbnRpY2F0aW9uJyB2YWx1ZT0ncHJpdmF0ZUtleScgLz4KICAgIDxwcm9wZXJ0eSBrZXk9J3NlcnZpY2UuTm9kZUV4ZWN1dG9yLmRlZmF1bHQucHJvdmlkZXInIHZhbHVlPSdqc2NoLXNzaCcgLz4KICAgIDxwcm9wZXJ0eSBrZXk9J3Jlc291cmNlcy5zb3VyY2UuMS5jb25maWcuaW5jbHVkZVNlcnZlck5vZGUnIHZhbHVlPSd0cnVlJyAvPgogICAgPHByb3BlcnR5IGtleT0ncmVzb3VyY2VzLnNvdXJjZS4xLmNvbmZpZy5nZW5lcmF0ZUZpbGVBdXRvbWF0aWNhbGx5JyB2YWx1ZT0ndHJ1ZScgLz4KICAgIDxwcm9wZXJ0eSBrZXk9J3Jlc291cmNlcy5zb3VyY2UuMS5jb25maWcuZmlsZScgdmFsdWU9Jy9Vc2Vycy9ncmVnL3J1bmRlY2syZC9wcm9qZWN0cy9tb25rZXkxL2V0Yy9yZXNvdXJjZXMueG1sJyAvPgogICAgPHByb3BlcnR5IGtleT0ncHJvamVjdC5zc2gta2V5cGF0aCcgdmFsdWU9Jy9Vc2Vycy9ncmVnLy5zc2gvaWRfcnNhJyAvPgogICAgPHByb3BlcnR5IGtleT0nc2VydmljZS5GaWxlQ29waWVyLmRlZmF1bHQucHJvdmlkZXInIHZhbHVlPSdqc2NoLXNjcCcgLz4KICAgIDxwcm9wZXJ0eSBrZXk9J3Jlc291cmNlcy5zb3VyY2UuMS50eXBlJyB2YWx1ZT0nZmlsZScgLz4KICA8L2NvbmZpZz4KPC9wcm9qZWN0Pg==
diff --git a/src/test/resources/org/rundeck/api/parser/projectv11.xml b/src/test/resources/org/rundeck/api/parser/projectv11.xml
new file mode 100644
index 0000000..e47e69d
--- /dev/null
+++ b/src/test/resources/org/rundeck/api/parser/projectv11.xml
@@ -0,0 +1,17 @@
+
+ ziggy
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From 92eb7acc1531c36711ed3d7672803d3cb30fa7c8 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Thu, 27 Feb 2014 12:44:26 -0800
Subject: [PATCH 38/89] Add get Project/config endpoint
---
.../java/org/rundeck/api/RundeckClient.java | 22 ++++++++++++++++-
.../org/rundeck/api/RundeckClientTest.java | 11 +++++++++
.../betamax/tapes/get_project_configv11.yaml | 24 +++++++++++++++++++
3 files changed, 56 insertions(+), 1 deletion(-)
create mode 100644 src/test/resources/betamax/tapes/get_project_configv11.yaml
diff --git a/src/main/java/org/rundeck/api/RundeckClient.java b/src/main/java/org/rundeck/api/RundeckClient.java
index 57ae3af..cd3739e 100644
--- a/src/main/java/org/rundeck/api/RundeckClient.java
+++ b/src/main/java/org/rundeck/api/RundeckClient.java
@@ -349,7 +349,7 @@ public class RundeckClient implements Serializable {
RundeckApiException, RundeckApiLoginException,
RundeckApiTokenException, IllegalArgumentException {
- AssertUtil.notBlank(projectName, "projectName is mandatory to get the details of a project !");
+ AssertUtil.notBlank(projectName, "projectName is mandatory to create a project !");
return new ApiCall(this)
.post(new ApiPathBuilder("/projects").xml(
projectDocument(projectName, configuration)
@@ -359,6 +359,26 @@ public class RundeckClient implements Serializable {
: "/project"
)));
}
+ /**
+ * Return the configuration of a project
+ *
+ * @param projectName name of the project - mandatory
+ *
+ * @return a {@link ProjectConfig} instance - 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 projectName is blank (null, empty or whitespace)
+ */
+ public ProjectConfig getProjectConfig(String projectName) throws
+ RundeckApiException, RundeckApiLoginException,
+ RundeckApiTokenException, IllegalArgumentException {
+
+ AssertUtil.notBlank(projectName, "projectName is mandatory to get the config of a project !");
+ return new ApiCall(this)
+ .get(new ApiPathBuilder("/project/", projectName, "/config"), new ProjectConfigParser("/config"));
+ }
private Document projectDocument(String projectName, Map configuration) {
RundeckProject project = new RundeckProject();
diff --git a/src/test/java/org/rundeck/api/RundeckClientTest.java b/src/test/java/org/rundeck/api/RundeckClientTest.java
index c66ea7c..4ab1fe7 100644
--- a/src/test/java/org/rundeck/api/RundeckClientTest.java
+++ b/src/test/java/org/rundeck/api/RundeckClientTest.java
@@ -91,6 +91,17 @@ public class RundeckClientTest {
Assert.assertNotNull(project.getProjectConfig());
}
+
+ @Test
+ @Betamax(tape = "get_project_configv11")
+ public void getProjectConfig() throws Exception {
+ ProjectConfig config = createClient(TEST_TOKEN_6, 11).getProjectConfig("monkey1");
+ Assert.assertNotNull(config);
+ Assert.assertNotNull(config.getProperties());
+ Assert.assertEquals(9,config.getProperties().size());
+ Assert.assertEquals("monkey1", config.getProperties().get("project.name"));
+ }
+
@Test
@Betamax(tape = "get_history")
public void getHistory() throws Exception {
diff --git a/src/test/resources/betamax/tapes/get_project_configv11.yaml b/src/test/resources/betamax/tapes/get_project_configv11.yaml
new file mode 100644
index 0000000..033aa13
--- /dev/null
+++ b/src/test/resources/betamax/tapes/get_project_configv11.yaml
@@ -0,0 +1,24 @@
+!tape
+name: get_project_configv11
+interactions:
+- recorded: 2014-02-27T20:35:47.282Z
+ request:
+ method: GET
+ uri: http://rundeck.local:4440/api/11/project/monkey1/config
+ headers:
+ Accept: text/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: Do4d3NUD5DKk21DR4sNK755RcPk618vn
+ response:
+ status: 200
+ headers:
+ Content-Type: application/xml;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=bo96n10n268hsd1gi9y67nah;Path=/
+ X-Rundeck-API-Version: '11'
+ X-Rundeck-API-XML-Response-Wrapper: 'false'
+ body: !!binary |-
+ PGNvbmZpZz4KICA8cHJvcGVydHkga2V5PSdwcm9qZWN0Lm5hbWUnIHZhbHVlPSdtb25rZXkxJyAvPgogIDxwcm9wZXJ0eSBrZXk9J3Byb2plY3Quc3NoLWF1dGhlbnRpY2F0aW9uJyB2YWx1ZT0ncHJpdmF0ZUtleScgLz4KICA8cHJvcGVydHkga2V5PSdzZXJ2aWNlLk5vZGVFeGVjdXRvci5kZWZhdWx0LnByb3ZpZGVyJyB2YWx1ZT0nanNjaC1zc2gnIC8+CiAgPHByb3BlcnR5IGtleT0ncmVzb3VyY2VzLnNvdXJjZS4xLmNvbmZpZy5pbmNsdWRlU2VydmVyTm9kZScgdmFsdWU9J3RydWUnIC8+CiAgPHByb3BlcnR5IGtleT0ncmVzb3VyY2VzLnNvdXJjZS4xLmNvbmZpZy5nZW5lcmF0ZUZpbGVBdXRvbWF0aWNhbGx5JyB2YWx1ZT0ndHJ1ZScgLz4KICA8cHJvcGVydHkga2V5PSdyZXNvdXJjZXMuc291cmNlLjEuY29uZmlnLmZpbGUnIHZhbHVlPScvVXNlcnMvZ3JlZy9ydW5kZWNrMmQvcHJvamVjdHMvbW9ua2V5MS9ldGMvcmVzb3VyY2VzLnhtbCcgLz4KICA8cHJvcGVydHkga2V5PSdwcm9qZWN0LnNzaC1rZXlwYXRoJyB2YWx1ZT0nL1VzZXJzL2dyZWcvLnNzaC9pZF9yc2EnIC8+CiAgPHByb3BlcnR5IGtleT0nc2VydmljZS5GaWxlQ29waWVyLmRlZmF1bHQucHJvdmlkZXInIHZhbHVlPSdqc2NoLXNjcCcgLz4KICA8cHJvcGVydHkga2V5PSdyZXNvdXJjZXMuc291cmNlLjEudHlwZScgdmFsdWU9J2ZpbGUnIC8+CjwvY29uZmlnPg==
From e548c14b242f393406fb46f22b276d085b7366d2 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Fri, 7 Mar 2014 10:07:31 -0800
Subject: [PATCH 39/89] Add setProjectConfig for apiv11
---
src/main/java/org/rundeck/api/ApiCall.java | 36 ++++++++++------
.../java/org/rundeck/api/ApiPathBuilder.java | 13 ++++++
.../java/org/rundeck/api/RundeckClient.java | 25 ++++++++++-
.../api/generator/BaseDocGenerator.java | 18 ++++++++
.../api/generator/ProjectConfigGenerator.java | 34 +++++++++++++++
.../api/generator/ProjectGenerator.java | 18 +++-----
.../api/generator/XmlDocumentGenerator.java | 29 +++++++++++++
.../org/rundeck/api/RundeckClientTest.java | 14 +++++++
.../generator/ProjectConfigGeneratorTest.java | 41 +++++++++++++++++++
.../api/generator/ProjectGeneratorTest.java | 2 +-
.../betamax/tapes/set_project_configv11.yaml | 26 ++++++++++++
11 files changed, 230 insertions(+), 26 deletions(-)
create mode 100644 src/main/java/org/rundeck/api/generator/BaseDocGenerator.java
create mode 100644 src/main/java/org/rundeck/api/generator/ProjectConfigGenerator.java
create mode 100644 src/main/java/org/rundeck/api/generator/XmlDocumentGenerator.java
create mode 100644 src/test/java/org/rundeck/api/generator/ProjectConfigGeneratorTest.java
create mode 100644 src/test/resources/betamax/tapes/set_project_configv11.yaml
diff --git a/src/main/java/org/rundeck/api/ApiCall.java b/src/main/java/org/rundeck/api/ApiCall.java
index 1dc2059..8d9f857 100644
--- a/src/main/java/org/rundeck/api/ApiCall.java
+++ b/src/main/java/org/rundeck/api/ApiCall.java
@@ -16,19 +16,10 @@
package org.rundeck.api;
import org.apache.commons.lang.StringUtils;
-import org.apache.http.Header;
-import org.apache.http.HttpException;
-import org.apache.http.HttpRequest;
-import org.apache.http.HttpRequestInterceptor;
-import org.apache.http.HttpResponse;
-import org.apache.http.NameValuePair;
-import org.apache.http.ParseException;
+import org.apache.http.*;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
-import org.apache.http.client.methods.HttpDelete;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.client.methods.*;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
@@ -272,6 +263,27 @@ class ApiCall {
public T post(ApiPathBuilder apiPath, XmlNodeParser parser) throws RundeckApiException,
RundeckApiLoginException, RundeckApiTokenException {
HttpPost httpPost = new HttpPost(client.getUrl() + client.getApiEndpoint() + apiPath);
+ return requestWithEntity(apiPath, parser, httpPost);
+ }
+ /**
+ * Execute an HTTP PUT request to the RunDeck instance, on the given path. We will login first, and then execute
+ * the API call. At the end, the given parser will be used to convert the response to a more useful result object.
+ *
+ * @param apiPath on which we will make the HTTP request - see {@link ApiPathBuilder}
+ * @param parser used to parse the response
+ * @return the result of the call, as formatted by the parser
+ * @throws RundeckApiException in case of error when calling the API
+ * @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)
+ */
+ public T put(ApiPathBuilder apiPath, XmlNodeParser parser) throws RundeckApiException,
+ RundeckApiLoginException, RundeckApiTokenException {
+ HttpPut httpPut = new HttpPut(client.getUrl() + client.getApiEndpoint() + apiPath);
+ return requestWithEntity(apiPath, parser, httpPut);
+ }
+
+ private T requestWithEntity(ApiPathBuilder apiPath, XmlNodeParser parser, HttpEntityEnclosingRequestBase
+ httpPost) {
if(null!= apiPath.getAccept()) {
httpPost.setHeader("Accept", apiPath.getAccept());
}
@@ -344,7 +356,7 @@ class ApiCall {
* @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)
*/
- private ByteArrayInputStream execute(HttpRequestBase request) throws RundeckApiException, RundeckApiLoginException,
+ private ByteArrayInputStream execute(HttpUriRequest request) throws RundeckApiException, RundeckApiLoginException,
RundeckApiTokenException {
HttpClient httpClient = instantiateHttpClient();
try {
diff --git a/src/main/java/org/rundeck/api/ApiPathBuilder.java b/src/main/java/org/rundeck/api/ApiPathBuilder.java
index e749004..bf27ae9 100644
--- a/src/main/java/org/rundeck/api/ApiPathBuilder.java
+++ b/src/main/java/org/rundeck/api/ApiPathBuilder.java
@@ -27,6 +27,7 @@ import org.apache.commons.lang.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.dom4j.Document;
+import org.rundeck.api.generator.XmlDocumentGenerator;
import org.rundeck.api.util.ParametersUtil;
/**
@@ -280,6 +281,18 @@ class ApiPathBuilder {
}
return this;
}
+ /**
+ * When POSTing a request, add the given XMl Document as the content of the request.
+ *
+ * @param document XMl document to send
+ * @return this, for method chaining
+ */
+ public ApiPathBuilder xml(final XmlDocumentGenerator document) {
+ if (document != null) {
+ xmlDocument = document.generateXmlDocument();
+ }
+ return this;
+ }
/**
* @return all attachments to be POSTed, with their names
diff --git a/src/main/java/org/rundeck/api/RundeckClient.java b/src/main/java/org/rundeck/api/RundeckClient.java
index cd3739e..8cf1989 100644
--- a/src/main/java/org/rundeck/api/RundeckClient.java
+++ b/src/main/java/org/rundeck/api/RundeckClient.java
@@ -25,6 +25,7 @@ import org.rundeck.api.RundeckApiException.RundeckApiLoginException;
import org.rundeck.api.RundeckApiException.RundeckApiTokenException;
import org.rundeck.api.domain.*;
import org.rundeck.api.domain.RundeckExecution.ExecutionStatus;
+import org.rundeck.api.generator.ProjectConfigGenerator;
import org.rundeck.api.generator.ProjectGenerator;
import org.rundeck.api.parser.*;
import org.rundeck.api.query.ExecutionQuery;
@@ -379,6 +380,28 @@ public class RundeckClient implements Serializable {
return new ApiCall(this)
.get(new ApiPathBuilder("/project/", projectName, "/config"), new ProjectConfigParser("/config"));
}
+ /**
+ * Return the configuration of a project
+ *
+ * @param projectName name of the project - mandatory
+ *
+ * @return a {@link ProjectConfig} instance - 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 projectName is blank (null, empty or whitespace)
+ */
+ public ProjectConfig setProjectConfig(String projectName, Map configuration) throws
+ RundeckApiException, RundeckApiLoginException,
+ RundeckApiTokenException, IllegalArgumentException {
+
+ AssertUtil.notBlank(projectName, "projectName is mandatory to get the config of a project !");
+ return new ApiCall(this)
+ .put(new ApiPathBuilder("/project/", projectName, "/config")
+ .xml(new ProjectConfigGenerator(new ProjectConfig(configuration)))
+ , new ProjectConfigParser("/config"));
+ }
private Document projectDocument(String projectName, Map configuration) {
RundeckProject project = new RundeckProject();
@@ -386,7 +409,7 @@ public class RundeckClient implements Serializable {
if (null != configuration) {
project.setProjectConfig(new ProjectConfig(configuration));
}
- return new ProjectGenerator(project).generate();
+ return new ProjectGenerator(project).generateXmlDocument();
}
/*
diff --git a/src/main/java/org/rundeck/api/generator/BaseDocGenerator.java b/src/main/java/org/rundeck/api/generator/BaseDocGenerator.java
new file mode 100644
index 0000000..46bf574
--- /dev/null
+++ b/src/main/java/org/rundeck/api/generator/BaseDocGenerator.java
@@ -0,0 +1,18 @@
+package org.rundeck.api.generator;
+
+import org.dom4j.Document;
+import org.dom4j.DocumentFactory;
+
+/**
+ * BaseDocGenerator generates a document using the element as the root.
+ *
+ * @author greg
+ * @since 2014-02-27
+ */
+public abstract class BaseDocGenerator implements XmlDocumentGenerator {
+ @Override
+ public Document generateXmlDocument() {
+ return DocumentFactory.getInstance().createDocument(generateXmlElement());
+ }
+
+}
diff --git a/src/main/java/org/rundeck/api/generator/ProjectConfigGenerator.java b/src/main/java/org/rundeck/api/generator/ProjectConfigGenerator.java
new file mode 100644
index 0000000..547b154
--- /dev/null
+++ b/src/main/java/org/rundeck/api/generator/ProjectConfigGenerator.java
@@ -0,0 +1,34 @@
+package org.rundeck.api.generator;
+
+import org.dom4j.Document;
+import org.dom4j.DocumentFactory;
+import org.dom4j.Element;
+import org.rundeck.api.domain.ProjectConfig;
+
+/**
+ * ProjectConfigGenerator is ...
+ *
+ * @author greg
+ * @since 2014-02-27
+ */
+public class ProjectConfigGenerator extends BaseDocGenerator {
+ private ProjectConfig config;
+
+ public ProjectConfigGenerator(ProjectConfig config) {
+ this.config = config;
+ }
+
+ @Override
+ public Element generateXmlElement() {
+ Element configEl = DocumentFactory.getInstance().createElement("config");
+ if (null != config.getProperties()) {
+ for (String s : config.getProperties().keySet()) {
+ Element property = configEl.addElement("property");
+ property.addAttribute("key", s);
+ property.addAttribute("value", config.getProperties().get(s));
+ }
+ }
+ return configEl;
+ }
+
+}
diff --git a/src/main/java/org/rundeck/api/generator/ProjectGenerator.java b/src/main/java/org/rundeck/api/generator/ProjectGenerator.java
index 37a45a4..8960acf 100644
--- a/src/main/java/org/rundeck/api/generator/ProjectGenerator.java
+++ b/src/main/java/org/rundeck/api/generator/ProjectGenerator.java
@@ -12,27 +12,21 @@ import org.rundeck.api.domain.RundeckProject;
* @author greg
* @since 2014-02-27
*/
-public class ProjectGenerator {
+public class ProjectGenerator extends BaseDocGenerator {
RundeckProject project;
public ProjectGenerator(RundeckProject project) {
this.project = project;
}
- public Document generate() {
- Document projectDom = DocumentFactory.getInstance().createDocument();
- Element rootElem = projectDom.addElement("project");
+ @Override
+ public Element generateXmlElement() {
+ Element rootElem = DocumentFactory.getInstance().createElement("project");
rootElem.addElement("name").setText(project.getName());
ProjectConfig configuration = project.getProjectConfig();
if (null != configuration) {
-
- Element config = rootElem.addElement("config");
- for (String s : configuration.getProperties().keySet()) {
- Element property = config.addElement("property");
- property.addAttribute("key", s);
- property.addAttribute("value", configuration.getProperties().get(s));
- }
+ rootElem.add(new ProjectConfigGenerator(configuration).generateXmlElement());
}
- return projectDom;
+ return rootElem;
}
}
diff --git a/src/main/java/org/rundeck/api/generator/XmlDocumentGenerator.java b/src/main/java/org/rundeck/api/generator/XmlDocumentGenerator.java
new file mode 100644
index 0000000..7d3faf3
--- /dev/null
+++ b/src/main/java/org/rundeck/api/generator/XmlDocumentGenerator.java
@@ -0,0 +1,29 @@
+package org.rundeck.api.generator;
+
+import org.dom4j.Document;
+import org.dom4j.Element;
+import org.dom4j.Node;
+
+/**
+ * XmlDocumentGenerator is ...
+ *
+ * @author greg
+ * @since 2014-02-27
+ */
+public interface XmlDocumentGenerator {
+
+ /**
+ * Generate the XML {@link org.dom4j.Node}
+ *
+ * @return any object holding the converted value
+ */
+ Element generateXmlElement();
+ /**
+ * Generate the XML {@link org.dom4j.Node}
+ *
+ * @param node
+ *
+ * @return any object holding the converted value
+ */
+ Document generateXmlDocument();
+}
diff --git a/src/test/java/org/rundeck/api/RundeckClientTest.java b/src/test/java/org/rundeck/api/RundeckClientTest.java
index 4ab1fe7..0034aa6 100644
--- a/src/test/java/org/rundeck/api/RundeckClientTest.java
+++ b/src/test/java/org/rundeck/api/RundeckClientTest.java
@@ -101,6 +101,20 @@ public class RundeckClientTest {
Assert.assertEquals(9,config.getProperties().size());
Assert.assertEquals("monkey1", config.getProperties().get("project.name"));
}
+ @Test
+ @Betamax(tape = "set_project_configv11")
+ public void setProjectConfig() throws Exception {
+ HashMap config = new HashMap();
+ config.put("alphabetty", "spaghetti");
+ config.put("blha.blee", "a big amazing thingy so there.");
+ ProjectConfig result = createClient(TEST_TOKEN_6, 11).setProjectConfig("monkey1", config);
+ Assert.assertNotNull(result);
+ Assert.assertNotNull(result.getProperties());
+ Assert.assertEquals(3, result.getProperties().size());
+ Assert.assertEquals("monkey1", result.getProperties().get("project.name"));
+ Assert.assertEquals("spaghetti", result.getProperties().get("alphabetty"));
+ Assert.assertEquals("a big amazing thingy so there.", result.getProperties().get("blha.blee"));
+ }
@Test
@Betamax(tape = "get_history")
diff --git a/src/test/java/org/rundeck/api/generator/ProjectConfigGeneratorTest.java b/src/test/java/org/rundeck/api/generator/ProjectConfigGeneratorTest.java
new file mode 100644
index 0000000..aa6d5da
--- /dev/null
+++ b/src/test/java/org/rundeck/api/generator/ProjectConfigGeneratorTest.java
@@ -0,0 +1,41 @@
+package org.rundeck.api.generator;
+
+import junit.framework.Assert;
+import org.dom4j.Document;
+import org.dom4j.Element;
+import org.dom4j.io.XMLWriter;
+import org.junit.Test;
+import org.rundeck.api.domain.ProjectConfig;
+import org.rundeck.api.domain.RundeckProject;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * ProjectConfigGeneratorTest is ...
+ *
+ * @author greg
+ * @since 2014-02-27
+ */
+public class ProjectConfigGeneratorTest {
+ @Test
+ public void generate() throws Exception {
+ ProjectConfig config = new ProjectConfig();
+ config.setProperty("abc", "123");
+ config.setProperty("monkey.bonanza", "pale\ncomparison");
+
+ Document doc = new ProjectConfigGenerator(config).generateXmlDocument();
+ XMLWriter xmlWriter = new XMLWriter(System.out);
+ xmlWriter.write(doc);
+ xmlWriter.flush();
+ Element configElement = doc.getRootElement();
+ Assert.assertEquals("config", configElement.getName());
+ Assert.assertNotNull(configElement.selectSingleNode("property[1]"));
+ Assert.assertEquals("abc", configElement.selectSingleNode("property[1]/@key").getText());
+ Assert.assertEquals("123", configElement.selectSingleNode("property[1]/@value").getText());
+
+ Assert.assertNotNull(configElement.selectSingleNode("property[2]"));
+ Assert.assertEquals("monkey.bonanza", configElement.selectSingleNode("property[2]/@key").getText());
+ Assert.assertEquals("pale\ncomparison", configElement.selectSingleNode("property[2]/@value").getText());
+
+ }
+}
diff --git a/src/test/java/org/rundeck/api/generator/ProjectGeneratorTest.java b/src/test/java/org/rundeck/api/generator/ProjectGeneratorTest.java
index a9c5b1b..26beb33 100644
--- a/src/test/java/org/rundeck/api/generator/ProjectGeneratorTest.java
+++ b/src/test/java/org/rundeck/api/generator/ProjectGeneratorTest.java
@@ -17,7 +17,7 @@ public class ProjectGeneratorTest {
RundeckProject project = new RundeckProject();
project.setName("monkey1");
- Document doc = new ProjectGenerator(project).generate();
+ Document doc = new ProjectGenerator(project).generateXmlDocument();
Assert.assertEquals("project", doc.getRootElement().getName());
Assert.assertNotNull(doc.selectSingleNode("/project/name"));
Assert.assertEquals("monkey1", doc.selectSingleNode("/project/name").getText());
diff --git a/src/test/resources/betamax/tapes/set_project_configv11.yaml b/src/test/resources/betamax/tapes/set_project_configv11.yaml
new file mode 100644
index 0000000..573eeaa
--- /dev/null
+++ b/src/test/resources/betamax/tapes/set_project_configv11.yaml
@@ -0,0 +1,26 @@
+!tape
+name: set_project_configv11
+interactions:
+- recorded: 2014-02-27T21:00:27.197Z
+ request:
+ method: PUT
+ uri: http://rundeck.local:4440/api/11/project/monkey1/config
+ headers:
+ Accept: text/xml
+ Content-Type: application/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ Transfer-Encoding: chunked
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: Do4d3NUD5DKk21DR4sNK755RcPk618vn
+ response:
+ status: 200
+ headers:
+ Content-Type: application/xml;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=19npj7cd0hpm71nfljn7nlbvh8;Path=/
+ X-Rundeck-API-Version: '11'
+ X-Rundeck-API-XML-Response-Wrapper: 'false'
+ body: !!binary |-
+ PGNvbmZpZz4KICA8cHJvcGVydHkga2V5PSdwcm9qZWN0Lm5hbWUnIHZhbHVlPSdtb25rZXkxJyAvPgogIDxwcm9wZXJ0eSBrZXk9J2FscGhhYmV0dHknIHZhbHVlPSdzcGFnaGV0dGknIC8+CiAgPHByb3BlcnR5IGtleT0nYmxoYS5ibGVlJyB2YWx1ZT0nYSBiaWcgYW1hemluZyB0aGluZ3kgc28gdGhlcmUuJyAvPgo8L2NvbmZpZz4=
From 29459d9ee1195c054fe4f76f682eda1ebd1bece0 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Fri, 7 Mar 2014 12:16:10 -0800
Subject: [PATCH 40/89] Support http DELETE with expected 204 no content
---
src/main/java/org/rundeck/api/ApiCall.java | 31 ++++++++++++++++---
.../org/rundeck/api/RundeckApiException.java | 22 +++++++++++++
2 files changed, 48 insertions(+), 5 deletions(-)
diff --git a/src/main/java/org/rundeck/api/ApiCall.java b/src/main/java/org/rundeck/api/ApiCall.java
index 8d9f857..93993ad 100644
--- a/src/main/java/org/rundeck/api/ApiCall.java
+++ b/src/main/java/org/rundeck/api/ApiCall.java
@@ -325,6 +325,22 @@ class ApiCall {
RundeckApiLoginException, RundeckApiTokenException {
return execute(new HttpDelete(client.getUrl() + client.getApiEndpoint() + apiPath), parser);
}
+ /**
+ * Execute an HTTP DELETE request to the RunDeck instance, on the given path, and expect a 204 response.
+ *
+ * @param apiPath on which we will make the HTTP request - see {@link ApiPathBuilder}
+ * @throws RundeckApiException in case of error when calling the API
+ * @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)
+ */
+ public void delete(ApiPathBuilder apiPath) throws RundeckApiException,
+ RundeckApiLoginException, RundeckApiTokenException {
+
+ InputStream response = execute(new HttpDelete(client.getUrl() + client.getApiEndpoint() + apiPath));
+ if(null!=response){
+ throw new RundeckApiException("Unexpected Rundeck response content, expected no content!");
+ }
+ }
/**
* Execute an HTTP request to the RunDeck instance. We will login first, and then execute the API call. At the end,
@@ -377,7 +393,8 @@ class ApiCall {
// in case of error, we get a redirect to /api/error
// that we need to follow manually for POST and DELETE requests (as GET)
- if (response.getStatusLine().getStatusCode() / 100 == 3) {
+ int statusCode = response.getStatusLine().getStatusCode();
+ if (statusCode / 100 == 3) {
String newLocation = response.getFirstHeader("Location").getValue();
try {
EntityUtils.consume(response.getEntity());
@@ -387,22 +404,26 @@ class ApiCall {
request = new HttpGet(newLocation);
try {
response = httpClient.execute(request);
+ statusCode = response.getStatusLine().getStatusCode();
} catch (IOException e) {
throw new RundeckApiException("Failed to execute an HTTP GET on url : " + request.getURI(), e);
}
}
// check the response code (should be 2xx, even in case of error : error message is in the XML result)
- if (response.getStatusLine().getStatusCode() / 100 != 2) {
- if (response.getStatusLine().getStatusCode() == 403 &&
+ if (statusCode / 100 != 2) {
+ if (statusCode == 403 &&
(client.getToken() != null || client.getSessionID() != null)) {
throw new RundeckApiTokenException("Invalid Token or sessionID ! Got HTTP response '" + response.getStatusLine()
+ "' for " + request.getURI());
} else {
- throw new RundeckApiException("Invalid HTTP response '" + response.getStatusLine() + "' for "
- + request.getURI());
+ throw new RundeckApiException.RundeckApiHttpStatusException("Invalid HTTP response '" + response.getStatusLine() + "' for "
+ + request.getURI(), statusCode);
}
}
+ if(statusCode==204){
+ return null;
+ }
if (response.getEntity() == null) {
throw new RundeckApiException("Empty RunDeck response ! HTTP status line is : "
+ response.getStatusLine());
diff --git a/src/main/java/org/rundeck/api/RundeckApiException.java b/src/main/java/org/rundeck/api/RundeckApiException.java
index 141e905..2a5b1ca 100644
--- a/src/main/java/org/rundeck/api/RundeckApiException.java
+++ b/src/main/java/org/rundeck/api/RundeckApiException.java
@@ -82,5 +82,27 @@ public class RundeckApiException extends RuntimeException {
super(message, cause);
}
}
+ /**
+ * Error due to unexpected HTTP status
+ */
+ public static class RundeckApiHttpStatusException extends RundeckApiAuthException {
+
+ private static final long serialVersionUID = 1L;
+ private int statusCode;
+
+ public RundeckApiHttpStatusException(String message, int statusCode) {
+ super(message);
+ this.statusCode = statusCode;
+ }
+
+ public RundeckApiHttpStatusException(String message, Throwable cause, int statusCode) {
+ super(message, cause);
+ this.statusCode = statusCode;
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+ }
}
From f49aa63043b253944bffaf642bfc037c033e335c Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Fri, 7 Mar 2014 12:22:10 -0800
Subject: [PATCH 41/89] Support keyed config get/set/delete for apiv11
---
.../java/org/rundeck/api/RundeckClient.java | 87 +++++++++++++++++++
.../rundeck/api/domain/ConfigProperty.java | 68 +++++++++++++++
.../ProjectConfigPropertyGenerator.java | 28 ++++++
.../parser/ProjectConfigPropertyParser.java | 41 +++++++++
.../org/rundeck/api/RundeckClientTest.java | 29 +++++++
.../ProjectConfigPropertyParserTest.java | 48 ++++++++++
.../tapes/delete_project_config_keyedv11.yaml | 57 ++++++++++++
.../get_project_config_keyed_dne_v11.yaml | 22 +++++
.../tapes/get_project_config_keyedv11.yaml | 24 +++++
.../tapes/set_project_config_keyedv11.yaml | 26 ++++++
10 files changed, 430 insertions(+)
create mode 100644 src/main/java/org/rundeck/api/domain/ConfigProperty.java
create mode 100644 src/main/java/org/rundeck/api/generator/ProjectConfigPropertyGenerator.java
create mode 100644 src/main/java/org/rundeck/api/parser/ProjectConfigPropertyParser.java
create mode 100644 src/test/java/org/rundeck/api/parser/ProjectConfigPropertyParserTest.java
create mode 100644 src/test/resources/betamax/tapes/delete_project_config_keyedv11.yaml
create mode 100644 src/test/resources/betamax/tapes/get_project_config_keyed_dne_v11.yaml
create mode 100644 src/test/resources/betamax/tapes/get_project_config_keyedv11.yaml
create mode 100644 src/test/resources/betamax/tapes/set_project_config_keyedv11.yaml
diff --git a/src/main/java/org/rundeck/api/RundeckClient.java b/src/main/java/org/rundeck/api/RundeckClient.java
index 8cf1989..f32f457 100644
--- a/src/main/java/org/rundeck/api/RundeckClient.java
+++ b/src/main/java/org/rundeck/api/RundeckClient.java
@@ -26,6 +26,7 @@ import org.rundeck.api.RundeckApiException.RundeckApiTokenException;
import org.rundeck.api.domain.*;
import org.rundeck.api.domain.RundeckExecution.ExecutionStatus;
import org.rundeck.api.generator.ProjectConfigGenerator;
+import org.rundeck.api.generator.ProjectConfigPropertyGenerator;
import org.rundeck.api.generator.ProjectGenerator;
import org.rundeck.api.parser.*;
import org.rundeck.api.query.ExecutionQuery;
@@ -380,6 +381,92 @@ public class RundeckClient implements Serializable {
return new ApiCall(this)
.get(new ApiPathBuilder("/project/", projectName, "/config"), new ProjectConfigParser("/config"));
}
+ /**
+ * Get a single project configuration key
+ *
+ * @param projectName name of the project - mandatory
+ * @param key name of the configuration key
+ *
+ * @return value, or null if the value is not set
+ *
+ * @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 projectName is blank (null, empty or whitespace)
+ */
+ public String getProjectConfig(final String projectName, final String key) throws
+ RundeckApiException, RundeckApiLoginException,
+ RundeckApiTokenException, IllegalArgumentException {
+
+ AssertUtil.notBlank(projectName, "projectName is mandatory to get the config of a project !");
+ AssertUtil.notBlank(key, "key is mandatory to get the config key value!");
+
+ ConfigProperty configProperty = null;
+ try {
+ configProperty = new ApiCall(this)
+ .get(new ApiPathBuilder("/project/", projectName, "/config/", key),
+ new ProjectConfigPropertyParser("/property"));
+ } catch (RundeckApiException.RundeckApiHttpStatusException e) {
+ if(404==e.getStatusCode()){
+ return null;
+ }
+ throw e;
+ }
+ return configProperty.getValue();
+ }
+ /**
+ * Set a single project configuration property value
+ *
+ * @param projectName name of the project - mandatory
+ * @param key name of the configuration property
+ * @param value value of the property
+ *
+ * @return new value
+ *
+ * @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 projectName is blank (null, empty or whitespace)
+ */
+ public String setProjectConfig(final String projectName, final String key, final String value) throws
+ RundeckApiException, RundeckApiLoginException,
+ RundeckApiTokenException, IllegalArgumentException {
+
+ AssertUtil.notBlank(projectName, "projectName is mandatory to set the config of a project !");
+ AssertUtil.notBlank(key, "key is mandatory to set the config key value!");
+ AssertUtil.notBlank(value, "value is mandatory to set the config key value!");
+
+ final ConfigProperty configProperty = new ApiCall(this)
+ .put(new ApiPathBuilder("/project/", projectName, "/config/", key)
+ .xml(new ProjectConfigPropertyGenerator(new ConfigProperty(key, value))),
+ new ProjectConfigPropertyParser("/property"));
+
+ return configProperty.getValue();
+ }
+ /**
+ * Set a single project configuration property value
+ *
+ * @param projectName name of the project - mandatory
+ * @param key name of the configuration property
+ * @param value value of the property
+ *
+ * @return new value
+ *
+ * @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 projectName is blank (null, empty or whitespace)
+ */
+ public void deleteProjectConfig(final String projectName, final String key) throws
+ RundeckApiException, RundeckApiLoginException,
+ RundeckApiTokenException, IllegalArgumentException {
+
+ AssertUtil.notBlank(projectName, "projectName is mandatory to set the config of a project !");
+ AssertUtil.notBlank(key, "key is mandatory to set the config key value!");
+
+ new ApiCall(this).delete(new ApiPathBuilder("/project/", projectName, "/config/",
+ key).accept("application/xml"));
+ }
/**
* Return the configuration of a project
*
diff --git a/src/main/java/org/rundeck/api/domain/ConfigProperty.java b/src/main/java/org/rundeck/api/domain/ConfigProperty.java
new file mode 100644
index 0000000..d15d773
--- /dev/null
+++ b/src/main/java/org/rundeck/api/domain/ConfigProperty.java
@@ -0,0 +1,68 @@
+package org.rundeck.api.domain;
+
+import java.io.Serializable;
+
+/**
+ * ConfigProperty is a single configuration property key and value.
+ *
+ * @author greg
+ * @since 2014-03-07
+ */
+public class ConfigProperty implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+ private String key;
+ private String value;
+
+ public ConfigProperty() {
+ }
+
+ public ConfigProperty(String key, String value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof ConfigProperty)) return false;
+
+ ConfigProperty that = (ConfigProperty) o;
+
+ if (!key.equals(that.key)) return false;
+ if (!value.equals(that.value)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = key.hashCode();
+ result = 31 * result + value.hashCode();
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "ConfigProperty{" +
+ "key='" + key + '\'' +
+ ", value='" + value + '\'' +
+ '}';
+ }
+}
diff --git a/src/main/java/org/rundeck/api/generator/ProjectConfigPropertyGenerator.java b/src/main/java/org/rundeck/api/generator/ProjectConfigPropertyGenerator.java
new file mode 100644
index 0000000..f41766b
--- /dev/null
+++ b/src/main/java/org/rundeck/api/generator/ProjectConfigPropertyGenerator.java
@@ -0,0 +1,28 @@
+package org.rundeck.api.generator;
+
+import org.dom4j.DocumentFactory;
+import org.dom4j.Element;
+import org.rundeck.api.domain.ConfigProperty;
+
+/**
+ * ProjectConfigPropertyGenerator generates a {@literal } element representing a configuration property.
+ *
+ * @author greg
+ * @since 2014-03-07
+ */
+public class ProjectConfigPropertyGenerator extends BaseDocGenerator {
+ private ConfigProperty property;
+
+ public ProjectConfigPropertyGenerator(ConfigProperty property) {
+ this.property = property;
+ }
+
+ @Override
+ public Element generateXmlElement() {
+ Element propElem = DocumentFactory.getInstance().createElement("property");
+ propElem.addAttribute("key", property.getKey());
+ propElem.addAttribute("value", property.getValue());
+
+ return propElem;
+ }
+}
diff --git a/src/main/java/org/rundeck/api/parser/ProjectConfigPropertyParser.java b/src/main/java/org/rundeck/api/parser/ProjectConfigPropertyParser.java
new file mode 100644
index 0000000..9a57114
--- /dev/null
+++ b/src/main/java/org/rundeck/api/parser/ProjectConfigPropertyParser.java
@@ -0,0 +1,41 @@
+package org.rundeck.api.parser;
+
+import org.dom4j.Node;
+import org.rundeck.api.domain.ConfigProperty;
+
+/**
+ * ProjectConfigPropertyParser parses a {@literal } element representing
+ * a configuration property.
+ *
+ * @author greg
+ * @since 2014-03-07
+ */
+public class ProjectConfigPropertyParser implements XmlNodeParser {
+ private String xpath;
+
+ public ProjectConfigPropertyParser() {
+ }
+
+ public ProjectConfigPropertyParser(final String xpath) {
+ this.setXpath(xpath);
+ }
+
+ @Override
+ public ConfigProperty parseXmlNode(final Node node) {
+ final Node propnode = getXpath() != null ? node.selectSingleNode(getXpath()) : node;
+ final String key = propnode.valueOf("@key");
+ final String value = propnode.valueOf("@value");
+ final ConfigProperty config = new ConfigProperty();
+ config.setKey(key);
+ config.setValue(value);
+ return config;
+ }
+
+ public String getXpath() {
+ return xpath;
+ }
+
+ public void setXpath(final String xpath) {
+ this.xpath = xpath;
+ }
+}
diff --git a/src/test/java/org/rundeck/api/RundeckClientTest.java b/src/test/java/org/rundeck/api/RundeckClientTest.java
index 0034aa6..ad475fd 100644
--- a/src/test/java/org/rundeck/api/RundeckClientTest.java
+++ b/src/test/java/org/rundeck/api/RundeckClientTest.java
@@ -116,6 +116,35 @@ public class RundeckClientTest {
Assert.assertEquals("a big amazing thingy so there.", result.getProperties().get("blha.blee"));
}
+ @Test
+ @Betamax(tape = "get_project_config_keyedv11")
+ public void getProjectConfigKeyed() throws Exception {
+ String value = createClient(TEST_TOKEN_6, 11).getProjectConfig("ABC", "project.name");
+ Assert.assertNotNull(value);
+ Assert.assertEquals("ABC", value);
+ }
+ @Test
+ @Betamax(tape = "get_project_config_keyed_dne_v11")
+ public void getProjectConfigKeyedDNE() throws Exception {
+ String value = createClient(TEST_TOKEN_6, 11).getProjectConfig("ABC", "does-not-exist");
+ Assert.assertNull(value);
+ }
+ @Test
+ @Betamax(tape = "set_project_config_keyedv11")
+ public void setProjectConfigKeyed() throws Exception {
+ String value = createClient(TEST_TOKEN_6, 11).setProjectConfig("ABC", "monkey-burrito", "lemon pie");
+ Assert.assertNotNull(value);
+ Assert.assertEquals("lemon pie", value);
+ }
+ @Test
+ @Betamax(tape = "delete_project_config_keyedv11")
+ public void deleteProjectConfigKeyed() throws Exception {
+ RundeckClient client1 = createClient(TEST_TOKEN_6, 11);
+ Assert.assertEquals("7up", client1.setProjectConfig("ABC", "monkey-burrito", "7up"));
+ client1.deleteProjectConfig("ABC", "monkey-burrito");
+ String value=client1.getProjectConfig("ABC", "monkey-burrito");
+ Assert.assertNull(value);
+ }
@Test
@Betamax(tape = "get_history")
public void getHistory() throws Exception {
diff --git a/src/test/java/org/rundeck/api/parser/ProjectConfigPropertyParserTest.java b/src/test/java/org/rundeck/api/parser/ProjectConfigPropertyParserTest.java
new file mode 100644
index 0000000..0fcac10
--- /dev/null
+++ b/src/test/java/org/rundeck/api/parser/ProjectConfigPropertyParserTest.java
@@ -0,0 +1,48 @@
+package org.rundeck.api.parser;
+
+import junit.framework.Assert;
+import org.dom4j.Document;
+import org.junit.Test;
+import org.junit.runners.JUnit4;
+import org.rundeck.api.domain.ConfigProperty;
+import org.rundeck.api.domain.ProjectConfig;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+/**
+ * Test
+ *
+ * @author greg
+ * @since 2014-03-07
+ */
+public class ProjectConfigPropertyParserTest {
+ @Test
+ public void parseFromProject() throws Exception {
+ InputStream input = getClass().getResourceAsStream("projectv11.xml");
+ Document document = ParserHelper.loadDocument(input);
+
+ ConfigProperty config = new ProjectConfigPropertyParser("project/config/property[1]").parseXmlNode(document);
+ Assert.assertEquals("project.name", config.getKey());
+ Assert.assertEquals("ziggy", config.getValue());
+ /**
+ *
+
+
+ */
+ }
+ @Test
+ public void parseProperty() throws Exception {
+ Document document = ParserHelper.loadDocument(new ByteArrayInputStream((" ").getBytes()));
+
+ ConfigProperty config = new ProjectConfigPropertyParser("/property").parseXmlNode(document);
+ Assert.assertEquals("project.name", config.getKey());
+ Assert.assertEquals("ABC", config.getValue());
+ /**
+ *
+
+
+ */
+ }
+}
diff --git a/src/test/resources/betamax/tapes/delete_project_config_keyedv11.yaml b/src/test/resources/betamax/tapes/delete_project_config_keyedv11.yaml
new file mode 100644
index 0000000..c107f56
--- /dev/null
+++ b/src/test/resources/betamax/tapes/delete_project_config_keyedv11.yaml
@@ -0,0 +1,57 @@
+!tape
+name: delete_project_config_keyedv11
+interactions:
+- recorded: 2014-03-07T19:59:51.228Z
+ request:
+ method: PUT
+ uri: http://rundeck.local:4440/api/11/project/ABC/config/monkey-burrito
+ headers:
+ Accept: text/xml
+ Content-Type: application/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ Transfer-Encoding: chunked
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: Do4d3NUD5DKk21DR4sNK755RcPk618vn
+ response:
+ status: 200
+ headers:
+ Content-Type: application/xml;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=bolnwf54stai1bo049hylrsua;Path=/
+ X-Rundeck-API-Version: '11'
+ X-Rundeck-API-XML-Response-Wrapper: 'false'
+ body: !!binary |-
+ PHByb3BlcnR5IGtleT0nbW9ua2V5LWJ1cnJpdG8nIHZhbHVlPSc3dXAnIC8+
+- recorded: 2014-03-07T19:59:51.325Z
+ request:
+ method: DELETE
+ uri: http://rundeck.local:4440/api/11/project/ABC/config/monkey-burrito
+ headers:
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: Do4d3NUD5DKk21DR4sNK755RcPk618vn
+ response:
+ status: 204
+ headers:
+ Content-Type: text/html;charset=UTF-8
+ Server: Jetty(7.6.0.v20120127)
+- recorded: 2014-03-07T19:59:51.402Z
+ request:
+ method: GET
+ uri: http://rundeck.local:4440/api/11/project/ABC/config/monkey-burrito
+ headers:
+ Accept: text/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: Do4d3NUD5DKk21DR4sNK755RcPk618vn
+ response:
+ status: 404
+ headers:
+ Content-Type: text/xml;charset=UTF-8
+ Server: Jetty(7.6.0.v20120127)
+ X-Rundeck-API-Version: '11'
+ body: "\n \n property does not exist: monkey-burrito \n \n "
diff --git a/src/test/resources/betamax/tapes/get_project_config_keyed_dne_v11.yaml b/src/test/resources/betamax/tapes/get_project_config_keyed_dne_v11.yaml
new file mode 100644
index 0000000..d17090c
--- /dev/null
+++ b/src/test/resources/betamax/tapes/get_project_config_keyed_dne_v11.yaml
@@ -0,0 +1,22 @@
+!tape
+name: get_project_config_keyed_dne_v11
+interactions:
+- recorded: 2014-03-07T20:19:47.533Z
+ request:
+ method: GET
+ uri: http://rundeck.local:4440/api/11/project/ABC/config/does-not-exist
+ headers:
+ Accept: text/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: Do4d3NUD5DKk21DR4sNK755RcPk618vn
+ response:
+ status: 404
+ headers:
+ Content-Type: text/xml;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=2367tnltmmec14cn79ps4fam9;Path=/
+ X-Rundeck-API-Version: '11'
+ body: "\n \n property does not exist: does-not-exist \n \n "
diff --git a/src/test/resources/betamax/tapes/get_project_config_keyedv11.yaml b/src/test/resources/betamax/tapes/get_project_config_keyedv11.yaml
new file mode 100644
index 0000000..c0ba023
--- /dev/null
+++ b/src/test/resources/betamax/tapes/get_project_config_keyedv11.yaml
@@ -0,0 +1,24 @@
+!tape
+name: get_project_config_keyedv11
+interactions:
+- recorded: 2014-03-07T19:50:29.035Z
+ request:
+ method: GET
+ uri: http://rundeck.local:4440/api/11/project/ABC/config/project.name
+ headers:
+ Accept: text/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: Do4d3NUD5DKk21DR4sNK755RcPk618vn
+ response:
+ status: 200
+ headers:
+ Content-Type: application/xml;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=jgign9nyxeyp4istq65l86lp;Path=/
+ X-Rundeck-API-Version: '11'
+ X-Rundeck-API-XML-Response-Wrapper: 'false'
+ body: !!binary |-
+ PHByb3BlcnR5IGtleT0ncHJvamVjdC5uYW1lJyB2YWx1ZT0nQUJDJyAvPg==
diff --git a/src/test/resources/betamax/tapes/set_project_config_keyedv11.yaml b/src/test/resources/betamax/tapes/set_project_config_keyedv11.yaml
new file mode 100644
index 0000000..88cfd10
--- /dev/null
+++ b/src/test/resources/betamax/tapes/set_project_config_keyedv11.yaml
@@ -0,0 +1,26 @@
+!tape
+name: set_project_config_keyedv11
+interactions:
+- recorded: 2014-03-07T19:59:51.009Z
+ request:
+ method: PUT
+ uri: http://rundeck.local:4440/api/11/project/ABC/config/monkey-burrito
+ headers:
+ Accept: text/xml
+ Content-Type: application/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ Transfer-Encoding: chunked
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: Do4d3NUD5DKk21DR4sNK755RcPk618vn
+ response:
+ status: 200
+ headers:
+ Content-Type: application/xml;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=3ssp8chdwsuw16hihk5frgpzy;Path=/
+ X-Rundeck-API-Version: '11'
+ X-Rundeck-API-XML-Response-Wrapper: 'false'
+ body: !!binary |-
+ PHByb3BlcnR5IGtleT0nbW9ua2V5LWJ1cnJpdG8nIHZhbHVlPSdsZW1vbiBwaWUnIC8+
From e8672e025b4f68b3acc0e7f7f64fd73983ef25c0 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Fri, 7 Mar 2014 12:35:52 -0800
Subject: [PATCH 42/89] Add deleteProject for apiv11
---
.../java/org/rundeck/api/RundeckClient.java | 17 +++++++++
.../org/rundeck/api/RundeckClientTest.java | 14 ++++++++
.../betamax/tapes/delete_projectv11.yaml | 36 +++++++++++++++++++
3 files changed, 67 insertions(+)
create mode 100644 src/test/resources/betamax/tapes/delete_projectv11.yaml
diff --git a/src/main/java/org/rundeck/api/RundeckClient.java b/src/main/java/org/rundeck/api/RundeckClient.java
index f32f457..1888684 100644
--- a/src/main/java/org/rundeck/api/RundeckClient.java
+++ b/src/main/java/org/rundeck/api/RundeckClient.java
@@ -361,6 +361,23 @@ public class RundeckClient implements Serializable {
: "/project"
)));
}
+ /**
+ * Delete a project
+ *
+ * @param projectName name of the project - mandatory
+ *
+ * @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 projectName is blank (null, empty or whitespace)
+ */
+ public void deleteProject(String projectName) throws
+ RundeckApiException, RundeckApiLoginException,
+ RundeckApiTokenException, IllegalArgumentException {
+
+ AssertUtil.notBlank(projectName, "projectName is mandatory to create a project !");
+ new ApiCall(this).delete(new ApiPathBuilder("/project/", projectName));
+ }
/**
* Return the configuration of a project
*
diff --git a/src/test/java/org/rundeck/api/RundeckClientTest.java b/src/test/java/org/rundeck/api/RundeckClientTest.java
index ad475fd..4396061 100644
--- a/src/test/java/org/rundeck/api/RundeckClientTest.java
+++ b/src/test/java/org/rundeck/api/RundeckClientTest.java
@@ -90,6 +90,20 @@ public class RundeckClientTest {
Assert.assertEquals(null, project.getDescription());
Assert.assertNotNull(project.getProjectConfig());
+ }
+ @Test
+ @Betamax(tape = "delete_projectv11")
+ public void deleteProject() throws Exception {
+ RundeckClient client1 = createClient(TEST_TOKEN_6, 11);
+ client1.deleteProject("delete_me");
+ RundeckProject delete_me = null;
+ try {
+ delete_me = client1.getProject("delete_me");
+ Assert.fail();
+ } catch (RundeckApiException.RundeckApiHttpStatusException e) {
+ Assert.assertEquals(404,e.getStatusCode());
+ }
+
}
@Test
diff --git a/src/test/resources/betamax/tapes/delete_projectv11.yaml b/src/test/resources/betamax/tapes/delete_projectv11.yaml
new file mode 100644
index 0000000..4025402
--- /dev/null
+++ b/src/test/resources/betamax/tapes/delete_projectv11.yaml
@@ -0,0 +1,36 @@
+!tape
+name: delete_projectv11
+interactions:
+- recorded: 2014-03-07T20:34:06.758Z
+ request:
+ method: DELETE
+ uri: http://rundeck.local:4440/api/11/project/delete_me
+ headers:
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: Do4d3NUD5DKk21DR4sNK755RcPk618vn
+ response:
+ status: 204
+ headers:
+ Content-Type: text/html;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=17vo5m2nghd0e1dcg0hqsuxklu;Path=/
+- recorded: 2014-03-07T20:34:06.903Z
+ request:
+ method: GET
+ uri: http://rundeck.local:4440/api/11/project/delete_me
+ headers:
+ Accept: text/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: Do4d3NUD5DKk21DR4sNK755RcPk618vn
+ response:
+ status: 404
+ headers:
+ Content-Type: text/xml;charset=UTF-8
+ Server: Jetty(7.6.0.v20120127)
+ X-Rundeck-API-Version: '11'
+ body: "\n \n project does not exist: delete_me \n \n "
From 2ffe87d428049f2d0313302a5eb354afdfbb5d46 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Fri, 7 Mar 2014 13:22:02 -0800
Subject: [PATCH 43/89] Update to support writing response content to a stream
---
src/main/java/org/rundeck/api/ApiCall.java | 123 ++++++++++++++++++---
1 file changed, 107 insertions(+), 16 deletions(-)
diff --git a/src/main/java/org/rundeck/api/ApiCall.java b/src/main/java/org/rundeck/api/ApiCall.java
index 93993ad..f3e7596 100644
--- a/src/main/java/org/rundeck/api/ApiCall.java
+++ b/src/main/java/org/rundeck/api/ApiCall.java
@@ -15,6 +15,7 @@
*/
package org.rundeck.api;
+import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.*;
import org.apache.http.client.HttpClient;
@@ -42,10 +43,7 @@ import org.rundeck.api.parser.XmlNodeParser;
import org.rundeck.api.util.AssertUtil;
import org.rundeck.api.util.DocumentContentProducer;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
+import java.io.*;
import java.net.ProxySelector;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
@@ -356,13 +354,35 @@ class ApiCall {
private T execute(HttpRequestBase request, XmlNodeParser parser) throws RundeckApiException,
RundeckApiLoginException, RundeckApiTokenException {
// execute the request
- InputStream response = execute(request);
-
- // read and parse the response
- Document xmlDocument = ParserHelper.loadDocument(response);
- return parser.parseXmlNode(xmlDocument);
+ return new ParserHandler(parser).handle(execute(request, new ResultHandler()));
}
+ /**
+ * Execute an HTTP GET request to the RunDeck instance, on the given path. We will login first, and then execute the
+ * API call. At the end, the given parser will be used to convert the response to a more useful result object.
+ *
+ * @param apiPath on which we will make the HTTP request - see {@link ApiPathBuilder}
+ * @param parser used to parse the response
+ *
+ * @return the result of the call, as formatted by the parser
+ *
+ * @throws RundeckApiException in case of error when calling the API
+ * @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)
+ */
+ public int get(ApiPathBuilder apiPath, OutputStream outputStream) throws RundeckApiException,
+ RundeckApiLoginException, RundeckApiTokenException, IOException {
+ HttpGet request = new HttpGet(client.getUrl() + client.getApiEndpoint() + apiPath);
+ if (null != apiPath.getAccept()) {
+ request.setHeader("Accept", apiPath.getAccept());
+ }
+ WriteOutHandler handler = new WriteOutHandler(outputStream);
+ int wrote = execute(request, handler);
+ if(handler.thrown!=null){
+ throw handler.thrown;
+ }
+ return wrote;
+ }
/**
* Execute an HTTP request to the RunDeck instance. We will login first, and then execute the API call.
*
@@ -374,6 +394,83 @@ class ApiCall {
*/
private ByteArrayInputStream execute(HttpUriRequest request) throws RundeckApiException, RundeckApiLoginException,
RundeckApiTokenException {
+ return execute(request, new ResultHandler() );
+ }
+
+ /**
+ * Handles one type into another
+ * @param
+ * @param
+ */
+ private static interface Handler{
+ public V handle(T response);
+ }
+
+ /**
+ * Handles parsing inputstream via a parser
+ * @param
+ */
+ private static class ParserHandler implements Handler {
+ XmlNodeParser parser;
+
+ private ParserHandler(XmlNodeParser parser) {
+ this.parser = parser;
+ }
+
+ @Override
+ public S handle(InputStream response) {
+ // read and parse the response
+ return parser.parseXmlNode(ParserHelper.loadDocument(response));
+ }
+ }
+
+ /**
+ * Handles writing response to an output stream
+ */
+ private static class WriteOutHandler implements Handler {
+ private WriteOutHandler(OutputStream writeOut) {
+ this.writeOut = writeOut;
+ }
+
+ OutputStream writeOut;
+ IOException thrown;
+ @Override
+ public Integer handle(final HttpResponse response) {
+ try {
+ return IOUtils.copy(response.getEntity().getContent(), writeOut);
+ } catch (IOException e) {
+ thrown=e;
+ }
+ return -1;
+ }
+ }
+
+ /**
+ * Handles reading response into a byte array stream
+ */
+ private static class ResultHandler implements Handler {
+ @Override
+ public ByteArrayInputStream handle(final HttpResponse response) {
+ // return a new inputStream, so that we can close all network resources
+ try {
+ return new ByteArrayInputStream(EntityUtils.toByteArray(response.getEntity()));
+ } catch (IOException e) {
+ throw new RundeckApiException("Failed to consume entity and convert the inputStream", e);
+ }
+ }
+ }
+ /**
+ * Execute an HTTP request to the RunDeck instance. We will login first, and then execute the API call.
+ *
+ * @param request to execute. see {@link HttpGet}, {@link HttpDelete}, and so on...
+ * @return a new {@link InputStream} instance, not linked with network resources
+ * @throws RundeckApiException in case of error when calling the API
+ * @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)
+ */
+ private T execute(HttpUriRequest request, Handler handler) throws RundeckApiException,
+ RundeckApiLoginException,
+ RundeckApiTokenException {
HttpClient httpClient = instantiateHttpClient();
try {
// we only need to manually login in case of login-based authentication
@@ -428,13 +525,7 @@ class ApiCall {
throw new RundeckApiException("Empty RunDeck response ! HTTP status line is : "
+ response.getStatusLine());
}
-
- // return a new inputStream, so that we can close all network resources
- try {
- return new ByteArrayInputStream(EntityUtils.toByteArray(response.getEntity()));
- } catch (IOException e) {
- throw new RundeckApiException("Failed to consume entity and convert the inputStream", e);
- }
+ return handler.handle(response);
} finally {
httpClient.getConnectionManager().shutdown();
}
From bea99b1c97157595be8c395ba74487451798abc3 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Fri, 7 Mar 2014 13:22:59 -0800
Subject: [PATCH 44/89] Add project export for apiv11
---
.../java/org/rundeck/api/RundeckClient.java | 49 +++++++++++++++++--
.../org/rundeck/api/RundeckClientTest.java | 10 ++++
.../betamax/tapes/export_projectv11.yaml | 23 +++++++++
3 files changed, 77 insertions(+), 5 deletions(-)
create mode 100644 src/test/resources/betamax/tapes/export_projectv11.yaml
diff --git a/src/main/java/org/rundeck/api/RundeckClient.java b/src/main/java/org/rundeck/api/RundeckClient.java
index 1888684..bfca253 100644
--- a/src/main/java/org/rundeck/api/RundeckClient.java
+++ b/src/main/java/org/rundeck/api/RundeckClient.java
@@ -34,11 +34,7 @@ import org.rundeck.api.util.AssertUtil;
import org.rundeck.api.util.PagedResults;
import org.rundeck.api.util.ParametersUtil;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Serializable;
+import java.io.*;
import java.util.*;
import java.util.concurrent.TimeUnit;
@@ -378,6 +374,49 @@ public class RundeckClient implements Serializable {
AssertUtil.notBlank(projectName, "projectName is mandatory to create a project !");
new ApiCall(this).delete(new ApiPathBuilder("/project/", projectName));
}
+ /**
+ * Convenience method to export the archive of a project to the specified file.
+ *
+ * @param projectName name of the project - mandatory
+ * @param out file to write to
+ * @return number of bytes written to the stream
+ *
+ * @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 projectName is blank (null, empty or whitespace)
+ */
+ public int exportProject(final String projectName, final File out) throws
+ RundeckApiException, RundeckApiLoginException,
+ RundeckApiTokenException, IllegalArgumentException, IOException {
+ final FileOutputStream fileOutputStream = new FileOutputStream(out);
+ try {
+ return exportProject(projectName, fileOutputStream);
+ }finally {
+ fileOutputStream.close();
+ }
+ }
+ /**
+ * Export the archive of a project to the specified outputstream
+ *
+ * @param projectName name of the project - mandatory
+ * @return number of bytes written to the stream
+ *
+ * @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 projectName is blank (null, empty or whitespace)
+ */
+ public int exportProject(String projectName, OutputStream out) throws
+ RundeckApiException, RundeckApiLoginException,
+ RundeckApiTokenException, IllegalArgumentException, IOException {
+
+ AssertUtil.notBlank(projectName, "projectName is mandatory to export a project archive!");
+ return new ApiCall(this).get(
+ new ApiPathBuilder("/project/", projectName, "/export")
+ .accept("application/zip"),
+ out);
+ }
/**
* Return the configuration of a project
*
diff --git a/src/test/java/org/rundeck/api/RundeckClientTest.java b/src/test/java/org/rundeck/api/RundeckClientTest.java
index 4396061..1b93bfa 100644
--- a/src/test/java/org/rundeck/api/RundeckClientTest.java
+++ b/src/test/java/org/rundeck/api/RundeckClientTest.java
@@ -28,6 +28,7 @@ import org.rundeck.api.query.ExecutionQuery;
import org.rundeck.api.util.PagedResults;
import java.io.ByteArrayInputStream;
+import java.io.File;
import java.io.InputStream;
import java.util.*;
@@ -160,6 +161,15 @@ public class RundeckClientTest {
Assert.assertNull(value);
}
@Test
+ @Betamax(tape = "export_projectv11")
+ public void exportProject() throws Exception {
+ RundeckClient client1 = createClient(TEST_TOKEN_6, 11);
+ File temp = File.createTempFile("test-archive", ".zip");
+ temp.deleteOnExit();
+ int i = client1.exportProject("DEF1", temp);
+ Assert.assertEquals(8705,i);
+ }
+ @Test
@Betamax(tape = "get_history")
public void getHistory() throws Exception {
final RundeckHistory test = client.getHistory("test");
diff --git a/src/test/resources/betamax/tapes/export_projectv11.yaml b/src/test/resources/betamax/tapes/export_projectv11.yaml
new file mode 100644
index 0000000..595c78d
--- /dev/null
+++ b/src/test/resources/betamax/tapes/export_projectv11.yaml
@@ -0,0 +1,23 @@
+!tape
+name: export_projectv11
+interactions:
+- recorded: 2014-03-07T21:12:45.024Z
+ request:
+ method: GET
+ uri: http://rundeck.local:4440/api/11/project/DEF1/export
+ headers:
+ Accept: application/zip
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: Do4d3NUD5DKk21DR4sNK755RcPk618vn
+ response:
+ status: 200
+ headers:
+ Content-Disposition: attachment; filename="DEF1-20140307-131244.rdproject.jar"
+ Content-Type: application/zip
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=18wgn0qj6x6ho1vpkwj2logftl;Path=/
+ body: !!binary |-
+ UEsDBBQACAgIAJZpZ0QAAAAAAAAAAAAAAAAUAAQATUVUQS1JTkYvTUFOSUZFU1QuTUb+ygAA803My0xLLS7RDUstKs7Mz7NSMNQz4OUKKs1LSU3O1nUsSs7ILEvVDSjKz0pNLtH1S8xNtVJwcXUzxFTjWlGQX1Si65JYAlRiZGBoomtgrGtgHmJkaGVoZGViEoWpxS2/KDcRp90FBTmZyYklQBmECiM9Az0j3WA/x4BgD/8QXi5eLgBQSwcIeFIRt4MAAADCAAAAUEsDBBQACAgIAJZpZ0QAAAAAAAAAAAAAAAANAAAAcnVuZGVjay1ERUYxLwMAUEsHCAAAAAACAAAAAAAAAFBLAwQUAAgICACWaWdEAAAAAAAAAAAAAAAAEgAAAHJ1bmRlY2stREVGMS9qb2JzLwMAUEsHCAAAAAACAAAAAAAAAFBLAwQUAAgICACWaWdEAAAAAAAAAAAAAAAAPgAAAHJ1bmRlY2stREVGMS9qb2JzL2pvYi02ZmQxODA4Yy1lYWZiLTQ5YWMtYWJmMi00ZGU3ZWM3NTg3MmYueG1sjVRRb9sgEH7vr+Bhkp9c1qpb0olYmrRV2ksbqdoPIHC2aQl4cFSJpv33YQiO3VbapChwx/fd3XccZk92p5XH5oIQFvfjGndKNp9bebX+uBY18HZX39xyUfNde13fSFiBWH1ar65bRiMwM7TtNLyAbn7c3z0wOpn51MOvAEYAeQYYOqtMt6larj1UxKPjCN1xUxkroW6V81hlWiQKu99zI4sdPXAA0YDoLekVwV55En8jlXz4PS6Xhu/hD6MJV8LQRRxGSz0nW4IXTg2orGkYnVv5fAyZcjKathen2gzCAackg7NPILD59v3uitFilVObAvqZkuwhY8QoPv5XxMW6lAO5qdAFqM7gV0UmvSOFoCWj0oBArHmn9qzXLjzF9qUdCyXMWFStEnxBieggBPi5gEGHThmCxyEKeOxB68eU/H4WYJswSyUxXau64PiyzHy9Bt0xjkmch6zkq+t8RV64DjFJRei/8FuO/YSnPz04TzsHHU2yjpe+fxUkyX+vnniHqfhZ25ZNYPRtq5hUfuAo+omFvQMuhQ0GmzgXc7NAplfRjNfO6NkuCDgIHSRsHQiQaXIz8q2/MBw3zw9Ogmu4F2BkjMbo2XkSsKyWhfDfLz9By8BIaJXG2OopfbabcUa/xJeZB668zdPh1MQFndH0HUpL+jT9BVBLBwgXu2wU9gEAAKQEAABQSwMEFAAICAgAlmlnRAAAAAAAAAAAAAAAAD4AAABydW5kZWNrLURFRjEvam9icy9qb2ItMDk0YjBkY2MtZWQ3NS00MTVmLTg0MDktMzFlNmIyMWI1MDJkLnhtbI1SwVLDIBC99yty4xRJaqJ2hjAetDNe9BsIbJBKIAJx6t9LSNNGvfTEe7tv9+0OSw621coHuskyEvH0RqQELXZVWwjOcxD3dV6VdZc/VMUuvy3hrt2WbV1sBcFROFdoKzV8gaYvr/s3gs90znr4HMFwyD4ABmmVkQ3qmPaAMh8cCyC/G2SsgLxTzgc0l8VCbvueGbHwGIEjcPpufTCsB4ITXdT4l5zgxfbEBXju1BCUNZTgNZvzU0fqexcITnBzGsEEOIazyeDsAXigT8/7kuCFbZYBVmJibFCd4uziEYPW+JFz8H69VM+UzhxwNSgwwTdIOpCP2nKmp11vEhI2ygzK8GXhP83i4P8syThe/Z1JOp0CTreQnnQeP1BLBwg2ZXStGgEAACgCAABQSwMEFAAICAgAlmlnRAAAAAAAAAAAAAAAAD4AAABydW5kZWNrLURFRjEvam9icy9qb2ItMmJlOTY2ZTctNDQwZS00ODk3LThhNTktNmFkMTI2ZGY2MDNlLnhtbL1SPW+DMBDd+RWOOjAhJ5SSIDmWoqaRurRLtyiDwQc4GJtiUyX/vg4fbdR2yNTp7t29p3c6PXLUqRTGUg8h4vpLdZ3gNEwhiWNYBlE0hyBaJctgxR6SIGZ8EcY8j+f3QLAjDgqpCwkfIOnzy+6V4C84bA28d6AyQBVAU2ihirWfM2nAR8a2zEJxXvtKcwhy0RrrDzInzHRdM8Un7CZwgoyW2ljFandADyc2/kH/Q26yVjSWtYVB+NeYktn+cbt52+zvZjgVCqfMlJ4HWalRrVUFZ2Q1KCakORwowaPqX+yFrBDv+A3Gbj2+e8QcBr7Qymmv0bC/fJKaurUhwX3vjdcrC6dvl6bVR8gs3T7tFgRPyJsuuCKTrrs5QT31kj7cx68vfSI/AVBLBwihKksFJgEAAJsCAABQSwMEFAAICAgAlmlnRAAAAAAAAAAAAAAAAD4AAABydW5kZWNrLURFRjEvam9icy9qb2ItZTZmNjFhZTItYWVlMS00NjEwLTlmZTktOGM2ZGYyY2U4ZGJjLnhtbI1Ty07DMBC85yt8QLKElJpUKGolxyeoxIUi8QWuvUndpnawHVSE+Hech9MUOHDyznpmd9YPejC7WjnPEoRoiLs1REoyyMs847BMOUCW3ufZXbouYZ2uRC7LpYCV3AlKAnFQ1Kaq4R1q9vS82VIywWHXwVsLWgA6AjSVUboqcMlrBxg5b7mH6qPA2khIS2Wdx4MsCIU5nbiWEQ8mLZRI8xMUGMTeYNQJXz00Bfa2BXwhBzq3FaqVDty0k6Cbz4696OIvjMisMBkqzzISnLCq8cpo1nVCRve9KJnvRKvkyislceYRzyV/FKCdI+ZNk1HSh8k4v/Zw9lOTxpoDCM8eHjeBGFESDczIVCrXcC/2k9bvLXApTKs9C+I5jJTpelh/O5RcEpECZ1G3El4sCJD9fN2hU/I7HxWW6+PWSrCMOwFahmqUXJKj+Wu7tG3//QZ76niI4XZKVXuwbmo/YLa4pWQMx44/yP0DYEm/9F/iG1BLBwjgWeRUbgEAABwDAABQSwMEFAAICAgAlmlnRAAAAAAAAAAAAAAAAD4AAABydW5kZWNrLURFRjEvam9icy9qb2ItM2Y2ODUzZjgtYjU4OS00ZGE4LWJhNzYtMTYzNmVmODExY2U2LnhtbI1TTU8DIRC976/gYEJispJau9aEclITL2riL6Awu0u7hRVYozH+d4H96Nr0YELCzPDezGMY6M5sG+U8yxCiwY57sJRky7JYr5blOt+u1nf5jeTB4rdFviiWBZTrxUJAQUkA9ozGVA18QMOenh9fKJnc/tTBewdaANoDtJVRutrgkjcOMHLecg/V1wY7D21eKus87mmBKMzhwLUc/V6khRJpfoANBlEbjLSR8BbIG+xtB/gIDnBuK9QoHbB5pKCL74i+ivYPRmSWmPSZZxEJTljVemU0i5WQ0akWJfOTUSo50XpGO3yC6DPVCsXromvka+VQWHNhlCTk+cyUjN0c/LmYlDT1cGrsGbU0VmHetNeUJDMbBGsPn36q21qzA+HZ/cPjgpLRy0ZNMzCVyrXci3ri+toCl8J02rNAnrsjZJoFlkaBkmMgmxommk7CqwUBMl05vnBsz2l8ZFiu9y9WgmXcCdAyZKPkGBzE/5VLu+7fA5+gQxPDe5Wq8WDdVL732dUlJYM5VDwBp2ljWdrS//sFUEsHCNNtNayRAQAAiQMAAFBLAwQUAAgICACWaWdEAAAAAAAAAAAAAAAAPgAAAHJ1bmRlY2stREVGMS9qb2JzL2pvYi1hYzc4ZGZiYi1hNDljLTQwYWItYWNkOS05NDA4YmU1NjFlNzQueG1sjVPLTsMwELznK3xAsoSUmkKhreT6BEhcKBJf4NqbxDS1g+0gEOLfsZ1HQ9UDUiTvbmZ2x5MNfTO7WjnPMoRoiOMZIiUZF8uVLHa7nC/WIl9c8RAJuc7Xi6vVDm7v5rBcUBKAHaM2ZQ0fULOn58ctJWPavXXw3oIWgPYATWmULje44LUDjJy33EP5tcHaSMgLZZ3HHS0QhTkcuJZD3om0UCDND7DBICqDUSS+emg22NsW8BEc4NyWqFY6YPNIQRffET2L8Q9GZNKYdJ0nFQlOWNV4ZTSLk5DRaRYl0zeDVHKi9Yx2+ATRdapUuDg06Br5SjkUnqkwShLyfGdKBjf7fCom9kDJw9HYM2ppnMK8aW4oSWHWC9YePv04t7HmDYRn9w+Pc0qGLBs0TcBUKtdwL6qR6ysLXArTas8CeZoOkHEXWFoFSo6FbDRM1K2EFwsCZLpy/MLRntP6wLBc77dWgmXcCdAydKPkWOzF/5VL2/bfC5+gvYnB60LVHqwbx3c5m11S0of9xBNw2jaWpSP9f79QSwcI9sg0SZEBAACJAwAAUEsDBBQACAgIAJZpZ0QAAAAAAAAAAAAAAAA+AAAAcnVuZGVjay1ERUYxL2pvYnMvam9iLTc1NmM5OWY3LTA0ZmItNDM4Yy04NGY1LTE3MjJkOTY3ZDFjYi54bWytVFtr2zAUfvevUNnAT5mWLm2aoQjCksIe1pSxPZVSFOnYVmNLniSX5N9Xlm9pmo11DAzyOfq+cz8ij3qTS+tohBDx//Xp/6Sg04tLPpsl09HHSbIZTT5d8dHVJLkYjafn52J2ORVjviHYAxtGrtMcniCnX2+u1wT3YnNr4VcFigPaApSpliqdxwnLLcTIOsMcpPt5rLSAUSKNdXFD80Sui4Ip0cleAzvgFHimUSYJDlIHxkfoE+zgwzooR2VepVIhty9hHnNd7hOZQzxAA10lMq18fFKrw5s6DOXM3qfj4xZgnVQBdMtcFqMnllfeKM50AdgI4FvsihLHCP/eSJ1Rz3Smgj+ira4Mh5feflowFqcGUux8RB9sdmSirs/JhAg+LstbShpakFt0nO7bmxPwNntlqU3nHw2a4v8ZtNzI0jGT2sPStmpKzu6+LBc/FnfvzvBGKrxhNouidlaRy6RF/mOogaN64ND778uHm/Vy9XCz+La6v6cEt8ZOR+Wv21VqZT98AV83lOBDqblXrAAKqVaNu3rQ0dg3vFZH3ZQ72A0OS6MfgTu6XF17YCdF/QQNYCKkLZnjWc91mQEmuK6Uo558KHaQ/gWg9ZQTPMgdAnY8rwTcGuAgQqoN8rW+YximtmvfXkOZ5aCEt0bwoGxjfxktqaq/fuUCtK2n3xRfSed3rXffyLSu6WdU15rgVhUN63VAIji8tOEIj+8zUEsHCLN18mQdAgAAhgUAAFBLAwQUAAgICACWaWdEAAAAAAAAAAAAAAAAPgAAAHJ1bmRlY2stREVGMS9qb2JzL2pvYi0zYWVjN2RmYi05NTAyLTQ4NzYtODc2My0xYWE3ODhjOGZjOWMueG1sjVNNb9QwEL3nV/iAlFN2aAvsFnlzgkpcaC/8ANeeOO4mdvBH1RXivzNONsluURGHyHkz782Mn23+5B47E2JdMMbpP6/0Z1R9I1BuVfNY3X58f1192G0/VfTdVFdCbHc7uWvkreRAxEnROd3hM3b1t+939xwWOGUD/kxoJbID4qCdsXpfNqILWLIQvYioj/vSOoVVY3yI5SQjoXR9L6yaMUVGVog4VEOXtLEsHgfcl9INx8Z0WK7UUW4boxN1MM6eZyiHNvojDUSdFYZo7Eh6ELEt2bPoEhWF1vUIXqE8QOwHePcrd99Y0ePvTSRRyeDtqihbt5SKPuE/2cElL/Gy/Y+APoD2qCF324T2VQkOb+yQw2ufFkvhwlMO89mcMHkhvRnGchzO0ZTPm69RO8uy3Sz7zq6pXQ4Xs+kRX+LScPDuCWWsv3y9u+Iwo2KZfyVzZcIgomwXbWw9CiVdsrEm8TmcKcuVqrPHHFY8M/BFdknhg0eJatzqxPw7Piu8sId7OndfiyDRKqrGYQ2eZr+clqf0389mpBbLfSYnI5300n7Cdfb0M8tecziFivVwz0Qcxqc7LuNr/gNQSwcIg9BA1bgBAADXAwAAUEsDBBQACAgIAJZpZ0QAAAAAAAAAAAAAAAA+AAAAcnVuZGVjay1ERUYxL2pvYnMvam9iLTg1OTZjYjljLTY4MzMtNDNmNy1hMGY3LTQ2NjNkZDhhYmMyOS54bWyNUrFuwjAQ3fkKd/JC5EJoGiRjCZUidSlLN4SEcS7BNNjUdij9+zpxUoLaocv53rt7z2fr6EHvSmkdGyBEfV6fPpMZSx+midhNRZSkcRxN4vwx4vc+TJIkzrKU78R4SolvDIpSFyWcoWQvr8sVJT8wVC18VKAEoHeAU6GlKmY456UFjKwz3EHxNcNKZxDl0liHg8wLhT4euco6XFsJI0+Om8Ii8otm9G79tJi/zdcg9hptK8WPsN1sGCVtQ2dMbpx9uZ2wxRmEfqmV1/ZRqNe+TCoLxq0a3lLScIN2bOXgcr3tZPQBhGOL5+WIkg51VR0ceq8JDKodZziAEUZnXlZgPaFg6PYGfPzU+OYb/hCOr8JcnmGY68oMrbz0hJTcjFB/Tm9+WlX/3oemtd4l0ixTczT79Q1QSwcI8UF0QDUBAABpAgAAUEsDBBQACAgIAJZpZ0QAAAAAAAAAAAAAAAA+AAAAcnVuZGVjay1ERUYxL2pvYnMvam9iLWQ0MDIzYTcyLTU0ZTEtNDFiNS1iNGQ0LTRkZDdlNWQ0ZjVlNC54bWyVUj1vwjAQ3fkV7uQlkZvUEYsTCZUidSlLN4REiC/B1LGp7VD67+vEoYDaoZ3s93Hv7NOxvd5KYV0xQYj5e3/6m+AFp/fpQzlN44xCEtNkm8VbymlMOZ9CxmmdAWXEG0OF1I2EI8ji+WWxZOQbBtXCeweqAvQGcGi0UE2O61JawMg6UzpoPnOsNIe4FsY6HMp8YaXbtlT8jPuoyoiDK01jEflBF+xu9Tifvc5WUO002nSqbGGzXheMjIZzMLlJ9vL4whFzCH6hla+9RkHvcwuhLBi3HHibMjKQk/HdysHp0u5g9B4qV8yfFgkjZ3RWdYi4+k5gUJ+Y4wASjI6l7Dx2OwMQuQ89MtZblCcudNtJJwaNe7vp/Jw5SNEKBybHEb4Z3S+90ktyLY4Q1bozkRWn/yQzcvOtfuJXM2Fd9+clG6z9gpJhQ4djWNovUEsHCHXrGxZLAQAAvgIAAFBLAwQUAAgICACWaWdEAAAAAAAAAAAAAAAAGAAAAHJ1bmRlY2stREVGMS9leGVjdXRpb25zLwMAUEsHCAAAAAACAAAAAAAAAFBLAwQUAAgICACWaWdEAAAAAAAAAAAAAAAAKgAAAHJ1bmRlY2stREVGMS9leGVjdXRpb25zL2V4ZWN1dGlvbi0xNDU3LnhtbG1TTW+cMBS851f4UIkT8bLdLZuV15e2kSJVSaXk1JuxH+As2Mg2TaKq/7025mM/KiHBvDfjN/MAAu/Aeye1svQGITJDJMUhyTbbPAl133nVxYOgX0qR7VY7ngIri3Rzx3jKinKdbgTkwPPtLl+XBEdu1Anm4Nkx40DQ9SrbpKvP6Sp/WWf7LNtv818EnzIWzVfddg38X3U3qhZO1FnHXG+pMz0QPILY0b3relfKBjrmahphGvLdGtHoiuALRpSVzGPxqAX8kNYhPM3pOQcQS4cKWSmm/NCrTlSwQod8xcd8BmeKQ+NPpyVrrPe7FEaJqZ6dkaqiqWItoGnEUo88776B39DQh8f7J4JnOK5SBydCWp+K1+NqLoqRqXzJx3dgxqUF9RllKLnaABNc98rRjOBTuJCOAF2lg8c4cMELB9550wv4aYD7hfnsI/e6vmgMU8cnI8BQZjko4U8keClOtvGlbxKD0bDIPfr0R3fhG78N8C/BYzOuAV/tgXRGvwJ39Nv3e594QrHX22BGtNK/meE5lt+0OZaNfkNz8kMyvOcEWWf8p1t9HJIwKS2lsS6ZjXLdtkyJsz0Bp8BrjWqJXC0t8leQ+hzhNqUYePMGzs4hePIz/OR4/svpzQmw9B9QSwcILXMgKd4BAAAOBAAAUEsDBBQACAgIAJZpZ0QAAAAAAAAAAAAAAAApAAAAcnVuZGVjay1ERUYxL2V4ZWN1dGlvbnMvb3V0cHV0LTE0NTcucmRsb2eLK0mtKNGv0C0qzUtJTc7WzclP1y0z0jOI44ozMjA00TUw1jUwDzEytDI0tDK1iKopLkktSEpNz8yrqanOy09JtU3JTM9LzAOL2xqCqeSSCiCrtDi1yDYxJTczr7YGl2EgA4g3LL0oNR23WSQYkZGpUJKRWawARCAtChAtWA22hDgyNS+FUidaQsKOWJMQIefq5xLHBQBQSwcIZFiSoZYAAACnAQAAUEsDBBQACAgIAJZpZ0QAAAAAAAAAAAAAAAAtAAAAcnVuZGVjay1ERUYxL2V4ZWN1dGlvbnMvc3RhdGUtMTQ1Ny5zdGF0ZS5qc29uzZFLq8IwEIX/y1lHaHzgNdvahRs36uZKF6EZpFDTkE5FKP3vN/HBRVDr0u08znznTAc6U9FyWduVgZLT2VzA1oYaqA6mPFhtofYdGiZX8BkKEuJ/acOaKRQ3uzTNsmW2RJ/3Ag35E/l10Am9m8rbLYGiPrqKmAIF+5YEWPsD8frKsr+r5AK6qp5UI2Bat5aDC4HWmXBiWx7jmXEip6NkMkrm27FUUqrZ4hdxQ3t+OfITR8iaIQ1yzSWgGNrF10Ny3XvTHyAMOBnEDAN9+Ehpbq97fOSVmtw99G+gzfs/UEsHCAUn/C3eAAAAlgIAAFBLAwQUAAgICACWaWdEAAAAAAAAAAAAAAAAFQAAAHJ1bmRlY2stREVGMS9yZXBvcnRzLwMAUEsHCAAAAAACAAAAAAAAAFBLAwQUAAgICACWaWdEAAAAAAAAAAAAAAAAJAAAAHJ1bmRlY2stREVGMS9yZXBvcnRzL3JlcG9ydC0xNDc0LnhtbG1Qz0+DMBS++1f04BVLkcm2ND2oM9GTyebFW2kfgwUooY9ki/F/tw/GnIlJk/Z9P9qvn+yhcz2qG8Zk6ywowWMuJB/PBGKFNSgwpWNlxbCsPAuLaHb7Rdtdqxv4lnwSksWjxsErPxgDYCU/z0Rpg5Vrd6cOfukrjCQGj++9O4BB9bx5CVGuAOKnwK92zCT5ZRzD6r1nfHppwNL1StumasMb00REA97rPag3lzPjmq4GBMvGNN4XQ12fJJ81pLcaYYu6DyqVxCKN4vsoznaJWAuxXmSfkl8rZsfTfPM/ntXZ86sh18FsjmDCR0S6yCS/jBMX0obzQ2HFMl6aCHSRR+lKm0jnRRKlFjIw2WKZJQVZJ/VYgy3deNNAJatC1x5CHX/Ri3Br+qrDucHc0ZceTx8eesLmstUPUEsHCGn21Ec3AQAANQIAAFBLAQIUABQACAgIAJZpZ0R4UhG3gwAAAMIAAAAUAAQAAAAAAAAAAAAAAAAAAABNRVRBLUlORi9NQU5JRkVTVC5NRv7KAABQSwECFAAUAAgICACWaWdEAAAAAAIAAAAAAAAADQAAAAAAAAAAAAAAAADJAAAAcnVuZGVjay1ERUYxL1BLAQIUABQACAgIAJZpZ0QAAAAAAgAAAAAAAAASAAAAAAAAAAAAAAAAAAYBAABydW5kZWNrLURFRjEvam9icy9QSwECFAAUAAgICACWaWdEF7tsFPYBAACkBAAAPgAAAAAAAAAAAAAAAABIAQAAcnVuZGVjay1ERUYxL2pvYnMvam9iLTZmZDE4MDhjLWVhZmItNDlhYy1hYmYyLTRkZTdlYzc1ODcyZi54bWxQSwECFAAUAAgICACWaWdENmV0rRoBAAAoAgAAPgAAAAAAAAAAAAAAAACqAwAAcnVuZGVjay1ERUYxL2pvYnMvam9iLTA5NGIwZGNjLWVkNzUtNDE1Zi04NDA5LTMxZTZiMjFiNTAyZC54bWxQSwECFAAUAAgICACWaWdEoSpLBSYBAACbAgAAPgAAAAAAAAAAAAAAAAAwBQAAcnVuZGVjay1ERUYxL2pvYnMvam9iLTJiZTk2NmU3LTQ0MGUtNDg5Ny04YTU5LTZhZDEyNmRmNjAzZS54bWxQSwECFAAUAAgICACWaWdE4FnkVG4BAAAcAwAAPgAAAAAAAAAAAAAAAADCBgAAcnVuZGVjay1ERUYxL2pvYnMvam9iLWU2ZjYxYWUyLWFlZTEtNDYxMC05ZmU5LThjNmRmMmNlOGRiYy54bWxQSwECFAAUAAgICACWaWdE0201rJEBAACJAwAAPgAAAAAAAAAAAAAAAACcCAAAcnVuZGVjay1ERUYxL2pvYnMvam9iLTNmNjg1M2Y4LWI1ODktNGRhOC1iYTc2LTE2MzZlZjgxMWNlNi54bWxQSwECFAAUAAgICACWaWdE9sg0SZEBAACJAwAAPgAAAAAAAAAAAAAAAACZCgAAcnVuZGVjay1ERUYxL2pvYnMvam9iLWFjNzhkZmJiLWE0OWMtNDBhYi1hY2Q5LTk0MDhiZTU2MWU3NC54bWxQSwECFAAUAAgICACWaWdEs3XyZB0CAACGBQAAPgAAAAAAAAAAAAAAAACWDAAAcnVuZGVjay1ERUYxL2pvYnMvam9iLTc1NmM5OWY3LTA0ZmItNDM4Yy04NGY1LTE3MjJkOTY3ZDFjYi54bWxQSwECFAAUAAgICACWaWdEg9BA1bgBAADXAwAAPgAAAAAAAAAAAAAAAAAfDwAAcnVuZGVjay1ERUYxL2pvYnMvam9iLTNhZWM3ZGZiLTk1MDItNDg3Ni04NzYzLTFhYTc4OGM4ZmM5Yy54bWxQSwECFAAUAAgICACWaWdE8UF0QDUBAABpAgAAPgAAAAAAAAAAAAAAAABDEQAAcnVuZGVjay1ERUYxL2pvYnMvam9iLTg1OTZjYjljLTY4MzMtNDNmNy1hMGY3LTQ2NjNkZDhhYmMyOS54bWxQSwECFAAUAAgICACWaWdEdesbFksBAAC+AgAAPgAAAAAAAAAAAAAAAADkEgAAcnVuZGVjay1ERUYxL2pvYnMvam9iLWQ0MDIzYTcyLTU0ZTEtNDFiNS1iNGQ0LTRkZDdlNWQ0ZjVlNC54bWxQSwECFAAUAAgICACWaWdEAAAAAAIAAAAAAAAAGAAAAAAAAAAAAAAAAACbFAAAcnVuZGVjay1ERUYxL2V4ZWN1dGlvbnMvUEsBAhQAFAAICAgAlmlnRC1zICneAQAADgQAACoAAAAAAAAAAAAAAAAA4xQAAHJ1bmRlY2stREVGMS9leGVjdXRpb25zL2V4ZWN1dGlvbi0xNDU3LnhtbFBLAQIUABQACAgIAJZpZ0RkWJKhlgAAAKcBAAApAAAAAAAAAAAAAAAAABkXAABydW5kZWNrLURFRjEvZXhlY3V0aW9ucy9vdXRwdXQtMTQ1Ny5yZGxvZ1BLAQIUABQACAgIAJZpZ0QFJ/wt3gAAAJYCAAAtAAAAAAAAAAAAAAAAAAYYAABydW5kZWNrLURFRjEvZXhlY3V0aW9ucy9zdGF0ZS0xNDU3LnN0YXRlLmpzb25QSwECFAAUAAgICACWaWdEAAAAAAIAAAAAAAAAFQAAAAAAAAAAAAAAAAA/GQAAcnVuZGVjay1ERUYxL3JlcG9ydHMvUEsBAhQAFAAICAgAlmlnRGn21Ec3AQAANQIAACQAAAAAAAAAAAAAAAAAhBkAAHJ1bmRlY2stREVGMS9yZXBvcnRzL3JlcG9ydC0xNDc0LnhtbFBLBQYAAAAAEwATAN4GAAANGwAAAAA=
From 97fa962311e938ec39008ae84c0401bdbce6f33e Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Sun, 9 Mar 2014 17:17:06 -0700
Subject: [PATCH 45/89] Support request content sent directly via file or
stream
---
src/main/java/org/rundeck/api/ApiCall.java | 9 ++++
.../java/org/rundeck/api/ApiPathBuilder.java | 51 +++++++++++++++++++
2 files changed, 60 insertions(+)
diff --git a/src/main/java/org/rundeck/api/ApiCall.java b/src/main/java/org/rundeck/api/ApiCall.java
index f3e7596..e285dee 100644
--- a/src/main/java/org/rundeck/api/ApiCall.java
+++ b/src/main/java/org/rundeck/api/ApiCall.java
@@ -24,7 +24,9 @@ import org.apache.http.client.methods.*;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
+import org.apache.http.entity.BasicHttpEntity;
import org.apache.http.entity.EntityTemplate;
+import org.apache.http.entity.FileEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.InputStreamBody;
@@ -298,6 +300,13 @@ class ApiCall {
} catch (UnsupportedEncodingException e) {
throw new RundeckApiException("Unsupported encoding: " + e.getMessage(), e);
}
+ }else if(apiPath.getContentStream() !=null && apiPath.getContentType()!=null){
+ BasicHttpEntity entity = new BasicHttpEntity();
+ entity.setContent(apiPath.getContentStream());
+ entity.setContentType(apiPath.getContentType());
+ httpPost.setEntity(entity);
+ }else if(apiPath.getContentFile() !=null && apiPath.getContentType()!=null){
+ httpPost.setEntity(new FileEntity(apiPath.getContentFile(), apiPath.getContentType()));
}else if(apiPath.getXmlDocument()!=null) {
httpPost.setHeader("Content-Type", "application/xml");
httpPost.setEntity(new EntityTemplate(new DocumentContentProducer(apiPath.getXmlDocument())));
diff --git a/src/main/java/org/rundeck/api/ApiPathBuilder.java b/src/main/java/org/rundeck/api/ApiPathBuilder.java
index bf27ae9..18a6194 100644
--- a/src/main/java/org/rundeck/api/ApiPathBuilder.java
+++ b/src/main/java/org/rundeck/api/ApiPathBuilder.java
@@ -15,6 +15,7 @@
*/
package org.rundeck.api;
+import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
@@ -46,6 +47,9 @@ class ApiPathBuilder {
private final Map attachments;
private final List form = new ArrayList();
private Document xmlDocument;
+ private InputStream contentStream;
+ private File contentFile;
+ private String contentType;
/** Marker for using the right separator between parameters ("?" or "&") */
private boolean firstParamDone = false;
@@ -59,6 +63,10 @@ class ApiPathBuilder {
public ApiPathBuilder(String... paths) {
apiPath = new StringBuilder();
attachments = new HashMap();
+ paths(paths);
+ }
+
+ public ApiPathBuilder paths(String... paths) {
if (paths != null) {
for (String path : paths) {
if (StringUtils.isNotBlank(path)) {
@@ -66,6 +74,7 @@ class ApiPathBuilder {
}
}
}
+ return this;
}
/**
@@ -269,6 +278,36 @@ class ApiPathBuilder {
}
return this;
}
+ /**
+ * When POSTing a request, use the given {@link InputStream} as the content of the request. This
+ * will only add the stream if it is not null.
+ *
+ * @param contentType MIME content type ofr hte request
+ * @param stream content stream
+ * @return this, for method chaining
+ */
+ public ApiPathBuilder content(final String contentType, final InputStream stream) {
+ if (stream != null && contentType != null) {
+ this.contentStream=stream;
+ this.contentType=contentType;
+ }
+ return this;
+ }
+ /**
+ * When POSTing a request, use the given {@link File} as the content of the request. This
+ * will only add the stream if it is not null.
+ *
+ * @param contentType MIME content type ofr hte request
+ * @param file content from a file
+ * @return this, for method chaining
+ */
+ public ApiPathBuilder content(final String contentType, final File file) {
+ if (file != null && contentType != null) {
+ this.contentFile=file;
+ this.contentType=contentType;
+ }
+ return this;
+ }
/**
* When POSTing a request, add the given XMl Document as the content of the request.
*
@@ -352,6 +391,18 @@ class ApiPathBuilder {
return xmlDocument;
}
+ public InputStream getContentStream() {
+ return contentStream;
+ }
+
+ public String getContentType() {
+ return contentType;
+ }
+
+ public File getContentFile() {
+ return contentFile;
+ }
+
/**
* BuildsParameters can add URL or POST parameters to an {@link ApiPathBuilder}
*
From 69d9c91ef822491637eb4c947b553865408d2825 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Sun, 9 Mar 2014 17:17:25 -0700
Subject: [PATCH 46/89] Add support for project archive import api v11
---
.../java/org/rundeck/api/RundeckClient.java | 38 ++++++++++
.../org/rundeck/api/domain/ArchiveImport.java | 38 ++++++++++
.../api/parser/ArchiveImportParser.java | 36 +++++++++
.../org/rundeck/api/RundeckClientTest.java | 45 ++++++++++-
.../tapes/import_project_failure_v11.yaml | 27 +++++++
.../betamax/tapes/import_project_suv11.yaml | 71 ++++++++++++++++++
.../org/rundeck/api/test-archive.zip | Bin 0 -> 8705 bytes
7 files changed, 251 insertions(+), 4 deletions(-)
create mode 100644 src/main/java/org/rundeck/api/domain/ArchiveImport.java
create mode 100644 src/main/java/org/rundeck/api/parser/ArchiveImportParser.java
create mode 100644 src/test/resources/betamax/tapes/import_project_failure_v11.yaml
create mode 100644 src/test/resources/betamax/tapes/import_project_suv11.yaml
create mode 100644 src/test/resources/org/rundeck/api/test-archive.zip
diff --git a/src/main/java/org/rundeck/api/RundeckClient.java b/src/main/java/org/rundeck/api/RundeckClient.java
index bfca253..666af9b 100644
--- a/src/main/java/org/rundeck/api/RundeckClient.java
+++ b/src/main/java/org/rundeck/api/RundeckClient.java
@@ -417,6 +417,44 @@ public class RundeckClient implements Serializable {
.accept("application/zip"),
out);
}
+
+ /**
+ * Import a archive file to the specified project.
+ *
+ * @param projectName name of the project - mandatory
+ * @param archiveFile zip archive file
+ * @param includeExecutions if true, import executions defined in the archive, otherwise skip them
+ * @param preserveJobUuids if true, do not remove UUIDs from imported jobs, otherwise remove them
+ *
+ * @return Result of the import request, may contain a list of import error messages
+ *
+ * @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 projectName is blank (null, empty or whitespace)
+ */
+ public ArchiveImport importArchive(final String projectName, final File archiveFile,
+ final boolean includeExecutions, final boolean preserveJobUuids) throws
+ RundeckApiException, RundeckApiLoginException,
+ RundeckApiTokenException, IllegalArgumentException, IOException {
+
+ AssertUtil.notBlank(projectName, "projectName is mandatory to import a project archive!");
+ AssertUtil.notNull(archiveFile, "archiveFile is mandatory to import a project archive!"); ;
+ return callImportProject(projectName, includeExecutions, preserveJobUuids,
+ new ApiPathBuilder().content("application/zip", archiveFile));
+ }
+
+ private ArchiveImport callImportProject(final String projectName, final boolean includeExecutions, final boolean preserveJobUuids,
+ final ApiPathBuilder param) {
+ param.paths("/project/", projectName, "/import")
+ .param("importExecutions", includeExecutions)
+ .param("jobUuidOption", preserveJobUuids ? "preserve" : "remove");
+ return new ApiCall(this).put(
+ param,
+ new ArchiveImportParser()
+ );
+ }
+
/**
* Return the configuration of a project
*
diff --git a/src/main/java/org/rundeck/api/domain/ArchiveImport.java b/src/main/java/org/rundeck/api/domain/ArchiveImport.java
new file mode 100644
index 0000000..7be8112
--- /dev/null
+++ b/src/main/java/org/rundeck/api/domain/ArchiveImport.java
@@ -0,0 +1,38 @@
+package org.rundeck.api.domain;
+
+import java.util.List;
+
+/**
+ * ArchiveImport describes the result of an {@link org.rundeck.api.RundeckClient#importArchive(String, java.io.File,
+ * boolean, boolean)} request.
+ *
+ * @author greg
+ * @since 2014-03-09
+ */
+public class ArchiveImport {
+ private boolean successful;
+ private List errorMessages;
+
+ public ArchiveImport(final boolean successful, final List errorMessages) {
+ this.successful = successful;
+ this.errorMessages = errorMessages;
+ }
+
+ /**
+ * Return true if successful
+ * @return
+ */
+ public boolean isSuccessful() {
+ return successful;
+ }
+
+
+ /**
+ * Return a list of error messages if unsuccessful
+ * @return
+ */
+ public List getErrorMessages() {
+ return errorMessages;
+ }
+
+}
diff --git a/src/main/java/org/rundeck/api/parser/ArchiveImportParser.java b/src/main/java/org/rundeck/api/parser/ArchiveImportParser.java
new file mode 100644
index 0000000..b4e7bda
--- /dev/null
+++ b/src/main/java/org/rundeck/api/parser/ArchiveImportParser.java
@@ -0,0 +1,36 @@
+package org.rundeck.api.parser;
+
+import org.dom4j.Node;
+import org.rundeck.api.domain.ArchiveImport;
+
+import java.util.ArrayList;
+
+/**
+ * ArchiveImportParser is ...
+ *
+ * @author greg
+ * @since 2014-03-09
+ */
+public class ArchiveImportParser implements XmlNodeParser {
+ String xpath;
+
+ public ArchiveImportParser() {
+ }
+
+ public ArchiveImportParser(final String xpath) {
+ this.xpath = xpath;
+ }
+
+ @Override
+ public ArchiveImport parseXmlNode(final Node node) {
+ final Node importNode = xpath != null ? node.selectSingleNode(xpath) : node;
+
+ boolean issuccess = "successful".equals(importNode.valueOf("/import/@status"));
+ final ArrayList messages = new ArrayList();
+ for (final Object o : importNode.selectNodes("/import/errors/error")) {
+ messages.add(((Node) o).getText());
+ }
+
+ return new ArchiveImport(issuccess, messages);
+ }
+}
diff --git a/src/test/java/org/rundeck/api/RundeckClientTest.java b/src/test/java/org/rundeck/api/RundeckClientTest.java
index 1b93bfa..f0aa4b6 100644
--- a/src/test/java/org/rundeck/api/RundeckClientTest.java
+++ b/src/test/java/org/rundeck/api/RundeckClientTest.java
@@ -19,6 +19,7 @@ import betamax.Betamax;
import betamax.MatchRule;
import betamax.Recorder;
import betamax.TapeMode;
+import org.apache.commons.io.IOUtils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
@@ -27,9 +28,7 @@ import org.rundeck.api.domain.*;
import org.rundeck.api.query.ExecutionQuery;
import org.rundeck.api.util.PagedResults;
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.InputStream;
+import java.io.*;
import java.util.*;
@@ -167,7 +166,45 @@ public class RundeckClientTest {
File temp = File.createTempFile("test-archive", ".zip");
temp.deleteOnExit();
int i = client1.exportProject("DEF1", temp);
- Assert.assertEquals(8705,i);
+ Assert.assertEquals(8705, i);
+ }
+ @Test
+ @Betamax(tape = "import_project_suv11",mode = TapeMode.READ_ONLY)
+ public void importProjectSuccess() throws Exception {
+ RundeckClient client1 = createClient(TEST_TOKEN_6, 11);
+ InputStream resourceAsStream = getClass().getResourceAsStream("test-archive.zip");
+ File temp = File.createTempFile("test-archive", ".zip");
+ temp.deleteOnExit();
+ IOUtils.copy(resourceAsStream, new FileOutputStream(temp));
+ ArchiveImport def1 = client1.importArchive("DEF2", temp, true, true);
+ Assert.assertTrue(def1.isSuccessful());
+ Assert.assertEquals(0, def1.getErrorMessages().size());
+
+ ArchiveImport def2 = client1.importArchive("DEF2", temp, false, true);
+ Assert.assertTrue(def2.isSuccessful());
+ Assert.assertEquals(0, def2.getErrorMessages().size());
+
+ ArchiveImport def3 = client1.importArchive("DEF2", temp, true, false);
+ Assert.assertTrue(def3.isSuccessful());
+ Assert.assertEquals(0, def3.getErrorMessages().size());
+ temp.delete();
+ }
+ @Test
+ @Betamax(tape = "import_project_failure_v11", mode = TapeMode.READ_ONLY)
+ public void importProjectFailure() throws Exception {
+ RundeckClient client1 = createClient(TEST_TOKEN_6, 11);
+ InputStream resourceAsStream = getClass().getResourceAsStream("test-archive.zip");
+ File temp = File.createTempFile("test-archive", ".zip");
+ temp.deleteOnExit();
+ IOUtils.copy(resourceAsStream, new FileOutputStream(temp));
+ ArchiveImport def1 = client1.importArchive("DEF1", temp, false, true);
+ Assert.assertFalse(def1.isSuccessful());
+ Assert.assertEquals(10, def1.getErrorMessages().size());
+ Assert.assertEquals("Job at index [1] at archive path: " +
+ "rundeck-DEF1/jobs/job-6fd1808c-eafb-49ac-abf2-4de7ec75872f.xml had errors: Validation errors: Cannot" +
+ " create a Job with UUID 6fd1808c-eafb-49ac-abf2-4de7ec75872f: a Job already exists with this UUID. " +
+ "Change the UUID or delete the other Job.", def1.getErrorMessages().get(0));
+
}
@Test
@Betamax(tape = "get_history")
diff --git a/src/test/resources/betamax/tapes/import_project_failure_v11.yaml b/src/test/resources/betamax/tapes/import_project_failure_v11.yaml
new file mode 100644
index 0000000..1ddcae5
--- /dev/null
+++ b/src/test/resources/betamax/tapes/import_project_failure_v11.yaml
@@ -0,0 +1,27 @@
+!tape
+name: import_project_failure_v11
+interactions:
+- recorded: 2014-03-10T00:01:12.170Z
+ request:
+ method: PUT
+ uri: http://rundeck.local:4440/api/11/project/DEF1/import?importExecutions=false&jobUuidOption=preserve
+ headers:
+ Accept: text/xml
+ Content-Length: '8705'
+ Content-Type: application/zip
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: Do4d3NUD5DKk21DR4sNK755RcPk618vn
+ body: ''
+ response:
+ status: 200
+ headers:
+ Content-Type: application/xml;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=1q6qo7ev7f5uz11hlfd8e0sa82;Path=/
+ X-Rundeck-API-Version: '11'
+ X-Rundeck-API-XML-Response-Wrapper: 'false'
+ body: !!binary |-
+ PGltcG9ydCBzdGF0dXM9J2ZhaWxlZCc+CiAgPGVycm9ycyBjb3VudD0nMTAnPgogICAgPGVycm9yPkpvYiBhdCBpbmRleCBbMV0gYXQgYXJjaGl2ZSBwYXRoOiBydW5kZWNrLURFRjEvam9icy9qb2ItNmZkMTgwOGMtZWFmYi00OWFjLWFiZjItNGRlN2VjNzU4NzJmLnhtbCBoYWQgZXJyb3JzOiBWYWxpZGF0aW9uIGVycm9yczogQ2Fubm90IGNyZWF0ZSBhIEpvYiB3aXRoIFVVSUQgNmZkMTgwOGMtZWFmYi00OWFjLWFiZjItNGRlN2VjNzU4NzJmOiBhIEpvYiBhbHJlYWR5IGV4aXN0cyB3aXRoIHRoaXMgVVVJRC4gQ2hhbmdlIHRoZSBVVUlEIG9yIGRlbGV0ZSB0aGUgb3RoZXIgSm9iLjwvZXJyb3I+CiAgICA8ZXJyb3I+Sm9iIGF0IGluZGV4IFsxXSBhdCBhcmNoaXZlIHBhdGg6IHJ1bmRlY2stREVGMS9qb2JzL2pvYi0wOTRiMGRjYy1lZDc1LTQxNWYtODQwOS0zMWU2YjIxYjUwMmQueG1sIGhhZCBlcnJvcnM6IFZhbGlkYXRpb24gZXJyb3JzOiBDYW5ub3QgY3JlYXRlIGEgSm9iIHdpdGggVVVJRCAwOTRiMGRjYy1lZDc1LTQxNWYtODQwOS0zMWU2YjIxYjUwMmQ6IGEgSm9iIGFscmVhZHkgZXhpc3RzIHdpdGggdGhpcyBVVUlELiBDaGFuZ2UgdGhlIFVVSUQgb3IgZGVsZXRlIHRoZSBvdGhlciBKb2IuPC9lcnJvcj4KICAgIDxlcnJvcj5Kb2IgYXQgaW5kZXggWzFdIGF0IGFyY2hpdmUgcGF0aDogcnVuZGVjay1ERUYxL2pvYnMvam9iLTJiZTk2NmU3LTQ0MGUtNDg5Ny04YTU5LTZhZDEyNmRmNjAzZS54bWwgaGFkIGVycm9yczogVmFsaWRhdGlvbiBlcnJvcnM6IENhbm5vdCBjcmVhdGUgYSBKb2Igd2l0aCBVVUlEIDJiZTk2NmU3LTQ0MGUtNDg5Ny04YTU5LTZhZDEyNmRmNjAzZTogYSBKb2IgYWxyZWFkeSBleGlzdHMgd2l0aCB0aGlzIFVVSUQuIENoYW5nZSB0aGUgVVVJRCBvciBkZWxldGUgdGhlIG90aGVyIEpvYi48L2Vycm9yPgogICAgPGVycm9yPkpvYiBhdCBpbmRleCBbMV0gYXQgYXJjaGl2ZSBwYXRoOiBydW5kZWNrLURFRjEvam9icy9qb2ItZTZmNjFhZTItYWVlMS00NjEwLTlmZTktOGM2ZGYyY2U4ZGJjLnhtbCBoYWQgZXJyb3JzOiBWYWxpZGF0aW9uIGVycm9yczogQ2Fubm90IGNyZWF0ZSBhIEpvYiB3aXRoIFVVSUQgZTZmNjFhZTItYWVlMS00NjEwLTlmZTktOGM2ZGYyY2U4ZGJjOiBhIEpvYiBhbHJlYWR5IGV4aXN0cyB3aXRoIHRoaXMgVVVJRC4gQ2hhbmdlIHRoZSBVVUlEIG9yIGRlbGV0ZSB0aGUgb3RoZXIgSm9iLjwvZXJyb3I+CiAgICA8ZXJyb3I+Sm9iIGF0IGluZGV4IFsxXSBhdCBhcmNoaXZlIHBhdGg6IHJ1bmRlY2stREVGMS9qb2JzL2pvYi0zZjY4NTNmOC1iNTg5LTRkYTgtYmE3Ni0xNjM2ZWY4MTFjZTYueG1sIGhhZCBlcnJvcnM6IFZhbGlkYXRpb24gZXJyb3JzOiBDYW5ub3QgY3JlYXRlIGEgSm9iIHdpdGggVVVJRCAzZjY4NTNmOC1iNTg5LTRkYTgtYmE3Ni0xNjM2ZWY4MTFjZTY6IGEgSm9iIGFscmVhZHkgZXhpc3RzIHdpdGggdGhpcyBVVUlELiBDaGFuZ2UgdGhlIFVVSUQgb3IgZGVsZXRlIHRoZSBvdGhlciBKb2IuPC9lcnJvcj4KICAgIDxlcnJvcj5Kb2IgYXQgaW5kZXggWzFdIGF0IGFyY2hpdmUgcGF0aDogcnVuZGVjay1ERUYxL2pvYnMvam9iLWFjNzhkZmJiLWE0OWMtNDBhYi1hY2Q5LTk0MDhiZTU2MWU3NC54bWwgaGFkIGVycm9yczogVmFsaWRhdGlvbiBlcnJvcnM6IENhbm5vdCBjcmVhdGUgYSBKb2Igd2l0aCBVVUlEIGFjNzhkZmJiLWE0OWMtNDBhYi1hY2Q5LTk0MDhiZTU2MWU3NDogYSBKb2IgYWxyZWFkeSBleGlzdHMgd2l0aCB0aGlzIFVVSUQuIENoYW5nZSB0aGUgVVVJRCBvciBkZWxldGUgdGhlIG90aGVyIEpvYi48L2Vycm9yPgogICAgPGVycm9yPkpvYiBhdCBpbmRleCBbMV0gYXQgYXJjaGl2ZSBwYXRoOiBydW5kZWNrLURFRjEvam9icy9qb2ItNzU2Yzk5ZjctMDRmYi00MzhjLTg0ZjUtMTcyMmQ5NjdkMWNiLnhtbCBoYWQgZXJyb3JzOiBWYWxpZGF0aW9uIGVycm9yczogQ2Fubm90IGNyZWF0ZSBhIEpvYiB3aXRoIFVVSUQgNzU2Yzk5ZjctMDRmYi00MzhjLTg0ZjUtMTcyMmQ5NjdkMWNiOiBhIEpvYiBhbHJlYWR5IGV4aXN0cyB3aXRoIHRoaXMgVVVJRC4gQ2hhbmdlIHRoZSBVVUlEIG9yIGRlbGV0ZSB0aGUgb3RoZXIgSm9iLjwvZXJyb3I+CiAgICA8ZXJyb3I+Sm9iIGF0IGluZGV4IFsxXSBhdCBhcmNoaXZlIHBhdGg6IHJ1bmRlY2stREVGMS9qb2JzL2pvYi0zYWVjN2RmYi05NTAyLTQ4NzYtODc2My0xYWE3ODhjOGZjOWMueG1sIGhhZCBlcnJvcnM6IFZhbGlkYXRpb24gZXJyb3JzOiBDYW5ub3QgY3JlYXRlIGEgSm9iIHdpdGggVVVJRCAzYWVjN2RmYi05NTAyLTQ4NzYtODc2My0xYWE3ODhjOGZjOWM6IGEgSm9iIGFscmVhZHkgZXhpc3RzIHdpdGggdGhpcyBVVUlELiBDaGFuZ2UgdGhlIFVVSUQgb3IgZGVsZXRlIHRoZSBvdGhlciBKb2IuPC9lcnJvcj4KICAgIDxlcnJvcj5Kb2IgYXQgaW5kZXggWzFdIGF0IGFyY2hpdmUgcGF0aDogcnVuZGVjay1ERUYxL2pvYnMvam9iLTg1OTZjYjljLTY4MzMtNDNmNy1hMGY3LTQ2NjNkZDhhYmMyOS54bWwgaGFkIGVycm9yczogVmFsaWRhdGlvbiBlcnJvcnM6IENhbm5vdCBjcmVhdGUgYSBKb2Igd2l0aCBVVUlEIDg1OTZjYjljLTY4MzMtNDNmNy1hMGY3LTQ2NjNkZDhhYmMyOTogYSBKb2IgYWxyZWFkeSBleGlzdHMgd2l0aCB0aGlzIFVVSUQuIENoYW5nZSB0aGUgVVVJRCBvciBkZWxldGUgdGhlIG90aGVyIEpvYi48L2Vycm9yPgogICAgPGVycm9yPkpvYiBhdCBpbmRleCBbMV0gYXQgYXJjaGl2ZSBwYXRoOiBydW5kZWNrLURFRjEvam9icy9qb2ItZDQwMjNhNzItNTRlMS00MWI1LWI0ZDQtNGRkN2U1ZDRmNWU0LnhtbCBoYWQgZXJyb3JzOiBWYWxpZGF0aW9uIGVycm9yczogQ2Fubm90IGNyZWF0ZSBhIEpvYiB3aXRoIFVVSUQgZDQwMjNhNzItNTRlMS00MWI1LWI0ZDQtNGRkN2U1ZDRmNWU0OiBhIEpvYiBhbHJlYWR5IGV4aXN0cyB3aXRoIHRoaXMgVVVJRC4gQ2hhbmdlIHRoZSBVVUlEIG9yIGRlbGV0ZSB0aGUgb3RoZXIgSm9iLjwvZXJyb3I+CiAgPC9lcnJvcnM+CjwvaW1wb3J0Pg==
diff --git a/src/test/resources/betamax/tapes/import_project_suv11.yaml b/src/test/resources/betamax/tapes/import_project_suv11.yaml
new file mode 100644
index 0000000..a8530d8
--- /dev/null
+++ b/src/test/resources/betamax/tapes/import_project_suv11.yaml
@@ -0,0 +1,71 @@
+!tape
+name: import_project_suv11
+interactions:
+- recorded: 2014-03-09T23:57:25.471Z
+ request:
+ method: PUT
+ uri: http://rundeck.local:4440/api/11/project/DEF2/import?importExecutions=true&jobUuidOption=preserve
+ headers:
+ Accept: text/xml
+ Content-Length: '8705'
+ Content-Type: application/zip
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: Do4d3NUD5DKk21DR4sNK755RcPk618vn
+ body: ''
+ response:
+ status: 200
+ headers:
+ Content-Type: application/xml;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=10hrj0jebdc621ukdlal6qqyu3;Path=/
+ X-Rundeck-API-Version: '11'
+ X-Rundeck-API-XML-Response-Wrapper: 'false'
+ body: !!binary |-
+ PGltcG9ydCBzdGF0dXM9J3N1Y2Nlc3NmdWwnIC8+
+- recorded: 2014-03-09T23:57:26.403Z
+ request:
+ method: PUT
+ uri: http://rundeck.local:4440/api/11/project/DEF2/import?importExecutions=false&jobUuidOption=preserve
+ headers:
+ Accept: text/xml
+ Content-Length: '8705'
+ Content-Type: application/zip
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: Do4d3NUD5DKk21DR4sNK755RcPk618vn
+ body: ''
+ response:
+ status: 200
+ headers:
+ Content-Type: application/xml;charset=UTF-8
+ Server: Jetty(7.6.0.v20120127)
+ X-Rundeck-API-Version: '11'
+ X-Rundeck-API-XML-Response-Wrapper: 'false'
+ body: !!binary |-
+ PGltcG9ydCBzdGF0dXM9J3N1Y2Nlc3NmdWwnIC8+
+- recorded: 2014-03-09T23:57:27.155Z
+ request:
+ method: PUT
+ uri: http://rundeck.local:4440/api/11/project/DEF2/import?importExecutions=true&jobUuidOption=remove
+ headers:
+ Accept: text/xml
+ Content-Length: '8705'
+ Content-Type: application/zip
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: Do4d3NUD5DKk21DR4sNK755RcPk618vn
+ body: ''
+ response:
+ status: 200
+ headers:
+ Content-Type: application/xml;charset=UTF-8
+ Server: Jetty(7.6.0.v20120127)
+ X-Rundeck-API-Version: '11'
+ X-Rundeck-API-XML-Response-Wrapper: 'false'
+ body: !!binary |-
+ PGltcG9ydCBzdGF0dXM9J3N1Y2Nlc3NmdWwnIC8+
diff --git a/src/test/resources/org/rundeck/api/test-archive.zip b/src/test/resources/org/rundeck/api/test-archive.zip
new file mode 100644
index 0000000000000000000000000000000000000000..e5a1dab3a2692e8004a0cd9f4ef7ec0d0afae89e
GIT binary patch
literal 8705
zcmbt(2UL^G);7ILk=~1dAP@*iNTGLy2+{GkZUKk3N!=jD?7bii#-A$w7nY2V)^3
zBhuA0Rt0G5X-Vs<>S=3f8W~IJYJKS>B3jq&?mCSGNcGVn0pdN~y^jomgW%~mG~zFi
z+PXc%zLGjU?UKkLI3KS7lR$mn;<7gBzHuKsBnhU2q}^(3QgE5w}sd;d}XwjvX&y!
zM^aLOm9Yu2Ik1_~&Ryk1zcp69DKiEc5-Iy>Ly(i|`wmmW7
z&treaFE63(Z73t#_8gbL4m8u^LgkmoY_h9iy2J2QqR#T_UE}LC6FDbUr5(0uN
zK0uy@xCf6|gN4mu>
z?nts1D5Z)$Z}dnbah`D4qcZ}fyIThzul3m_7^RZzCC4obqMOB(zL++*JdG!PlK+zY
zLC>_Q=J8sgh%Awu{t%U-3wc{bBT@=2Te-ZnBHd=j51DYPQSSuEcAkW&M(S~fwh7V%
zEUPZH#eWWFvrPpeMP#fBpHAUqa^spYt1M6kb3w3$SZi|U&efRnTQ)y9R#Ojo^vTE1!
zQ;rF(uil@ySe1HStG+oYnX>rVi-DQJX7cpD4PG7O9^`JIt`but|Wic3Z-0jz!z~
zuHO|PUj^8DgPY3rmW}|)`S(-EQv+JH8_hvA9@`)2k@QtVos>^IKul{JTKC8RerGMH
zdb}C8eXSFGla!5Hr0M}P#S@8cR<7g?25?hH30d6b`_d)*u+Uzgp1>WR2G4dSA_}L3
zSi1Ljwn9MsJhTG!+?b+}XGT4gkfath_x%jcvQ>`DLY{l>7lB2Tq0Cl;J4tENEnCgx
z0Urk$<7MNgWmDIUPQDLfr_%HE=4v2=UwPCqy-XaCb*6VeZaTs(k=Vq}&Q(8sc6s(_
z*ziuQ_iAvhac_JNkEg5{umN^T?$*swulspc9!yNo&Lf?x*cs&)v(sNCJK)v_>DqGX
zBzo1iGJN=y2`oUdJ`cI@EQsO5#jhj9uUP=uVG&R$76yPofLH(oj(`E+C|Lvmio(c%
zpcs275R4_TP;02@5e8(O*k!#T2NV>Ij}t&7-n}3Dv;tWz7S=!s=Sa0P68Tz3&+j(q
z*FL!TaiTWQUry0$FrTH>kU?;E59yme4LL0sg*KxwfJ6$Ii*(tx@Wlz(3fv;PeB3iMCUMlP#o1qlK@|E$^{cvjxd|k(GD3A{mw4hc^*mkhfcOjPAGj~BRkWcD)so-?cy4Qs^Vsx(s)~m^u=S!!~{mN#gXL4
z@rC!l+BH3CQ?tK?0{z
z9v+`!EaoiICixadP3c)l(@{da;I7S8hncIJFMRdHuor1v9+PTN}?_8-f~8BMla`
z=0tKNkOYIL;+`EYlpF|;Cz0=So{ye7g~X<}g-KFHAkrTv9%VQVh(EQ?%)-$;X*)=5
zqX;42sv^e;Qp#1c79`M*SKQ7@?Y&X^ZdN*`y$HxD-V0(%D=k>-bR70o)7q{TOJ30^
zobQwnIsf)(ugE2qtaPEby0;DbBRk;rTb^4+w_8(4se1YNV3#=znCQCOjm1YirMGSm
zuK+wxoGw(PokhgNF9w=jl8?7!iY0L{sAjU3q`Gy0o5(i$B+t*9xHLDcQyL>rY<|T#
z-ZCy{*QKVy?dt(W(EEU^Gk!W}gG$|{kGCNMjFZr<1(
z&nyq=zdLJSdnjBMY!3(6$-)u%Op3xkp5{B
zDvif+5tb68pCC`ENy$B|!;1D_r1MZlL
z*j2W6?qxU19V&WHcZoqU-qH*AvZ7b6)?M3T(846%*+_OcO08!$6o`dHC*11GXA@b!
zZ6J>53)GUwg}wt1(X=exb(wd0qi^PoiWi>W?T(L`;Q9RIPCR7O(|MV*5@LdytQd(G
z26L0SFk}W7jF~?ooq2uGG#47z*QKQk1}1b?jzx_P6Z+g}|JVI*>2APHwkQ@)e$>AtABBd&G4^(L02Bm)20(x)
z{1Y0303aYhxE)p&DuabV{^?k&Wj~zXBRgd$+=+n%WGh4ErF!I6GCAeo}pi)KGZE
z-QKV5Hr+)q;ar38=X#FwmJ(13v`6O8e>~M$}>Hl_`pQYcKwtp`_xgz=rug~{dauQMOg{t
z2jI!SeXGxjO=JKTX6$u$GsbU+tk1W=_%R&vj%!y3!IF^=)M5IBbI_rH?c>CcZ>e-N
z^}PZ+JEb)~b8;8cMh(*r^C=y`tIOWfg*$9B-1OGDBFPQWeg5s}7sM_}&|1yxDRKp8c_{Dca1e
z+Ng#lwIRMD?lyl!s+D1XleUwL`T3f5?Z)LeU6>Jq!SZ5Y#jn
zudCq@ds%=C3*nIudszd~NTpPffxb5F
za!y?(tF^u%;U^r|^A;BD{1B|@I>A?@+*-v0JQ)IcHXg+zWZQP$E;FX&*GNZ6;`0;5
z)7z-K0L|@kO+5GZFBDaT7#zFqdtQBAqc}SBL|=zBsr)oczkh
ze};la-}N(z?YgJ=1^wW1PT=&*{gtlB)J?BV&qq5|PwVr@s$2C=z9|_y>x@;#5!=Ax
zr`7YHm=+Py`~)4*zBOr`%tm&8w@glwE^T0pIU?o(wQn&W1e@Eekfhj~*hHrfmR5B;awD~cB#j7L(YO<3ucd{vIYpH<9I-CO|^HsT}S
zPZ(aju((40FH;Z-U%cVN5CDOf*Lb;y&p!AM7$Ac}!QgN-+#ZeikGRnF7z8rbE|~6w
z#2fiJ(k`=I@DA0nbd>%~G?D@Tc-(LGPZ!4l6;ioN&R$ftv+VOg9h&0In2Jmo(u=ENa&sroklwA702aMfsAE<*N@&Yu|^DU
zQdws!s4P@U64d
z^d8H%np`s3kTZ=&^y{zFfENU7Ia|GWdivsfQ%elwyUHgd_j`)-t?1bwEgrR*?e|>$
zNR2J3$JN%%0(0z=FNt_#8wKvVvb(t|(ui1i^oNU(l`2p8-2Gnz+Kkf
z@Q7=hp1m48t$FfNb1q*<340{$rOMD_e5M-tmzfGKi-4l-@JR{^2ZQm!3LmymK>Qa3
z3I$^@aFiVyg!q=J49nab2_*rI|0lJ1HAgOCG+6K^%^bUU+jgj^6hyFHc|z^^pQz
z2YAR)EeC58Tg7bKcUu&=&x1Q}xxX;pC~36JK;2pDJo50_MtJ;qjQ%A(k6`n&Une8)
zS5AubOB#7Y_BZJW1g)w1sL0|8a{8AQ0tNyEfl)9JKo&x%5b&ikzz%|e;1wkXhLy$O
z6ASj6lt{qWY~KiC{WvcYn>u(jn)$y3XGpue}W)SMkMnw`G9eST$mpsaRM
z2W2IrdUZGG(q8H`dEWM-Izo3YMvZ9zliFg@>2w;Asn+V0PK<5lR*x9G9xl{AyNfNu
z%yUx=H3m@@kZe$RI#%fG-dHj;f8H)(fr-QE#f??1Yk9E!7oo+H6UV
zYMy{p5a`zJwTaG##r}`B8+_uX-I;9ELJmGAzE>ab>DlUM-kBp}in)=ytl%e4%J_sq
z5j1QOFDm6TrY%ZwJ*Z~!a~k4Q9}VU4wxe~N6VkQ)NH4$*#-XR+Sk}C+!eFoUhrzR^
zV3gJNf(UofL1-LGJrZp;DovoxcZr(~iKngZx3qB_ZmD4duxMW&ClB}ktu-h98$W-$
z1js;SVT7~jW~A$p24s1LkJtK9%xmQnfYgMMq^j6sXSH+Z2UE-VrzKytLv`;Ke65AP
zMJtO7HavsP!PbdLR-OlmR+ev22!hmwTLe3xV+z#1Qx}F>!m@01Vn3M3XOKul`*^nn
zbYAmHcPE>FzWzbVCW-8%`yln(>DMxIDla$1$L(c~R-@9wmv|8~A-RQLk5tjMb*qRuZ_$(OI?f2$91&%+qUMCZ*pSAo{SPPTW)vu
z#Y`JLzIB7hDmSbR?%6;~IeB4#cE>4XKVo-TX!~iM;}N4aQK9Gh_6V_=Gr|EU^s3f!
zJ($A!O4}9pHctA_aM#nVN;jav#l$urF8gTJllX6pZ3krrsFjV3*=kkv*C)>)5~nH<
ziPwYGy+5ggo-L4_bNHNRagiqucmj}HCY5~MYoh9O)FVaWyyq_0oue!PfKR5k_IPHX
zxf}uO6g@qH0iVF1=L5cUExw>G-QXweK7hBtiAntKqyKHY?Zj_(jfby~r?1anTgD6H
z>fsPAq5V*-ujD1*Kdtc>9cM-W;C}Gcxocn$5Yi_L9F_$#$bc$9kP1-c)q)dJ+JI9!
zy1m_n`T0FvXS6GIJ5Ki^yGf(RxI**i<7fm5E8vywP#F;zxTK0A2_-;!6((6LCd*rW
zPM9M$HeWw3_FNH>h5&$u5nx7F6%Gfab^X
z-qRnrrKc%&umW3a(9~b*|De!=TR2TAXVm9)ZY<$)+`wzg=fhXH9?;)cFmub^;^jJS
zy2?qzG<(UZDdhwUtOoL;99yN4xlKa1%e?FRlDamva}03#uF}(McSy+h6Uof>N!Ru|
z%j*m0NuCyD7z^2&S0{$iULH>Nw6oxwOFn-rF9!qCc{^5SY*_Gmmi@eXP%z>X^U3xU
zK{~G&B3T@xEhFk)6F~#~0!QGS%|}Qt?woRRFA2iUC!~xkZg^z9*#FiJBp3Y*n8Ytj
z;%{RV>*0m-!g_jm`TTDIO88e!{&I$2`@afWH~ro-VL+C;ebbF;R%C2P6-4m?xbJqy
z+ZGEa{xEW}?3xF_N4X!tA
z8&7IHZ5OVOVP@~YvaXJ50a>R|`NW=F)JZ+HpvjcW1_HjeOBNwNC%S1C2ABvKP!TCq
z8{t#qz0?=&>9SYQ^rT_DFNyCAKVM+u+wvg>!kKs48axTZ9|75KY!Z{O5PiQ6`|*B>
za2@uu{pxZ|ANjKv!YI7+Z$`L_`feTg$Db~jem9hG6ZPFF@UQ&S&~NurhsXbTe?aI@
zf45WrIR1aRl{$>|W0(AAtOC49{=e@^!1~ksiNjbw_J4oI0^*Cdf5!ULF8pDvA3Ksi
zV>MFz3hPh%%ZIUkY=HfYl}7a|tUv8|9>)5y-|{n7GR?2B{
z(|*ojtRG9WpRxEEeuV}8!;<|l){j-j&sge5e}(m@rQcz!AEoinSo8SM@XvexPpg>2
zScEw7-;hNR+utpfc8tr5C-2(ne&kA|H_2JE`H2Y
h1X=Li!hhxBkVw!+lH&sw5fL-~Zxa7R$4&U}{{ihc>^T4c
literal 0
HcmV?d00001
From c12b2f1459cb9521023ac1f4ff1ed7380b5c8729 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Fri, 4 Apr 2014 09:55:48 -0700
Subject: [PATCH 47/89] API 11 status
---
src/site/confluence/status.confluence | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/src/site/confluence/status.confluence b/src/site/confluence/status.confluence
index 3a3d96b..edf1e5f 100644
--- a/src/site/confluence/status.confluence
+++ b/src/site/confluence/status.confluence
@@ -93,3 +93,17 @@ h2. RunDeck API version 10
* Execution Output - Retrieve log output for a particular node or step - OK
* Execution Info - added successfulNodes and failedNodes detail. - OK
* Deprecation: Remove methods deprecated until version 10. - OK
+
+
+h2. RunDeck API version 11
+
+[Documentation of the RunDeck API version 11|http://rundeck.org/2.1.0/api/index.html]
+
+* Project creation - OK
+* Get Project configuration - OK
+* Set Project configuration - OK
+* Get/Set Project configuration keys - OK
+* Delete project - OK
+* Export project archive - OK
+* Import project archive - OK
+* ...
From b5f4ec8ccd42eb371760c61d13d008e666952bdc Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Fri, 4 Apr 2014 09:57:20 -0700
Subject: [PATCH 48/89] Add todos for API v11
---
src/site/confluence/status.confluence | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/site/confluence/status.confluence b/src/site/confluence/status.confluence
index edf1e5f..9bc64f9 100644
--- a/src/site/confluence/status.confluence
+++ b/src/site/confluence/status.confluence
@@ -106,4 +106,10 @@ h2. RunDeck API version 11
* Delete project - OK
* Export project archive - OK
* Import project archive - OK
-* ...
+* SSH Key upload - *TODO*
+* SSH Key delete - *TODO*
+* SSH Key list - *TODO*
+* SSH Key get - *TODO*
+* API Token create - *TODO*
+* API Token list - *TODO*
+* API Token delete - *TODO*
From 0cb3da88ec2b38d6cbfd06adf64a22225be988aa Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Fri, 4 Apr 2014 11:40:24 -0700
Subject: [PATCH 49/89] Allow empty content in request
---
src/main/java/org/rundeck/api/ApiCall.java | 2 ++
src/main/java/org/rundeck/api/ApiPathBuilder.java | 13 +++++++++++++
2 files changed, 15 insertions(+)
diff --git a/src/main/java/org/rundeck/api/ApiCall.java b/src/main/java/org/rundeck/api/ApiCall.java
index e285dee..07e09f9 100644
--- a/src/main/java/org/rundeck/api/ApiCall.java
+++ b/src/main/java/org/rundeck/api/ApiCall.java
@@ -310,6 +310,8 @@ class ApiCall {
}else if(apiPath.getXmlDocument()!=null) {
httpPost.setHeader("Content-Type", "application/xml");
httpPost.setEntity(new EntityTemplate(new DocumentContentProducer(apiPath.getXmlDocument())));
+ }else if(apiPath.isEmptyContent()){
+ //empty content
}else {
throw new IllegalArgumentException("No Form or Multipart entity for POST content-body");
}
diff --git a/src/main/java/org/rundeck/api/ApiPathBuilder.java b/src/main/java/org/rundeck/api/ApiPathBuilder.java
index 18a6194..05250ec 100644
--- a/src/main/java/org/rundeck/api/ApiPathBuilder.java
+++ b/src/main/java/org/rundeck/api/ApiPathBuilder.java
@@ -50,6 +50,7 @@ class ApiPathBuilder {
private InputStream contentStream;
private File contentFile;
private String contentType;
+ private boolean emptyContent = false;
/** Marker for using the right separator between parameters ("?" or "&") */
private boolean firstParamDone = false;
@@ -308,6 +309,15 @@ class ApiPathBuilder {
}
return this;
}
+ /**
+ * When POSTing a request, send an empty request.
+ *
+ * @return this, for method chaining
+ */
+ public ApiPathBuilder emptyContent() {
+ this.emptyContent=true;
+ return this;
+ }
/**
* When POSTing a request, add the given XMl Document as the content of the request.
*
@@ -403,6 +413,9 @@ class ApiPathBuilder {
return contentFile;
}
+ public boolean isEmptyContent() {
+ return emptyContent;
+ }
/**
* BuildsParameters can add URL or POST parameters to an {@link ApiPathBuilder}
*
From 0f8e3387192c23942695f9c67d9e92771d153349 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Fri, 4 Apr 2014 11:41:09 -0700
Subject: [PATCH 50/89] Support API token endpoint (v11)
---
.../java/org/rundeck/api/RundeckClient.java | 64 ++++++++++++++
.../org/rundeck/api/domain/RundeckToken.java | 36 ++++++++
.../api/parser/RundeckTokenParser.java | 33 ++++++++
.../org/rundeck/api/RundeckClientTest.java | 84 +++++++++++++++++++
.../betamax/tapes/api_token_delete.yaml | 36 ++++++++
.../betamax/tapes/api_token_generate.yaml | 25 ++++++
.../betamax/tapes/api_token_get.yaml | 24 ++++++
.../betamax/tapes/api_tokens_list_all.yaml | 24 ++++++
.../betamax/tapes/api_tokens_list_user.yaml | 24 ++++++
9 files changed, 350 insertions(+)
create mode 100644 src/main/java/org/rundeck/api/domain/RundeckToken.java
create mode 100644 src/main/java/org/rundeck/api/parser/RundeckTokenParser.java
create mode 100644 src/test/resources/betamax/tapes/api_token_delete.yaml
create mode 100644 src/test/resources/betamax/tapes/api_token_generate.yaml
create mode 100644 src/test/resources/betamax/tapes/api_token_get.yaml
create mode 100644 src/test/resources/betamax/tapes/api_tokens_list_all.yaml
create mode 100644 src/test/resources/betamax/tapes/api_tokens_list_user.yaml
diff --git a/src/main/java/org/rundeck/api/RundeckClient.java b/src/main/java/org/rundeck/api/RundeckClient.java
index 666af9b..e56bda1 100644
--- a/src/main/java/org/rundeck/api/RundeckClient.java
+++ b/src/main/java/org/rundeck/api/RundeckClient.java
@@ -2310,6 +2310,70 @@ public class RundeckClient implements Serializable {
return new ApiCall(this).get(new ApiPathBuilder("/system/info"), new SystemInfoParser(rootXpath()+"/system"));
}
+
+ /*
+ * API token
+ */
+
+ /**
+ * List API tokens for a user.
+ * @param user username
+ * @return list of tokens
+ * @throws RundeckApiException
+ */
+ public List listApiTokens(final String user) throws RundeckApiException {
+ AssertUtil.notNull(user, "user is mandatory to list API tokens for a user.");
+ return new ApiCall(this).
+ get(new ApiPathBuilder("/tokens/", user),
+ new ListParser(new RundeckTokenParser(), "/tokens/token"));
+ }
+
+ /**
+ * List all API tokens
+ * @return list of tokens
+ * @throws RundeckApiException
+ */
+ public List listApiTokens() throws RundeckApiException {
+ return new ApiCall(this).
+ get(new ApiPathBuilder("/tokens"),
+ new ListParser(new RundeckTokenParser(), "/tokens/token"));
+ }
+
+ /**
+ * Generate an API token for a user.
+ * @param user
+ * @return
+ * @throws RundeckApiException
+ */
+ public String generateApiToken(final String user) throws RundeckApiException{
+ AssertUtil.notNull(user, "user is mandatory to generate an API token for a user.");
+ RundeckToken result = new ApiCall(this).
+ post(new ApiPathBuilder("/tokens/", user).emptyContent(),
+ new RundeckTokenParser("/token"));
+ return result.getToken();
+ }
+ /**
+ * Delete an existing token
+ * @param token
+ * @return
+ * @throws RundeckApiException
+ */
+ public boolean deleteApiToken(final String token) throws RundeckApiException{
+ AssertUtil.notNull(token, "token is mandatory to delete an API token.");
+ new ApiCall(this).delete(new ApiPathBuilder("/token/", token));
+ return true;
+ }
+ /**
+ * Return user info for an existing token
+ * @param token
+ * @return token info
+ * @throws RundeckApiException
+ */
+ public RundeckToken getApiToken(final String token) throws RundeckApiException{
+ AssertUtil.notNull(token, "token is mandatory to get an API token.");
+ return new ApiCall(this).get(new ApiPathBuilder("/token/", token), new RundeckTokenParser("/token"));
+ }
+
/**
* @return the URL of the RunDeck instance ("http://localhost:4440", "http://rundeck.your-compagny.com/", etc)
*/
diff --git a/src/main/java/org/rundeck/api/domain/RundeckToken.java b/src/main/java/org/rundeck/api/domain/RundeckToken.java
new file mode 100644
index 0000000..613fc82
--- /dev/null
+++ b/src/main/java/org/rundeck/api/domain/RundeckToken.java
@@ -0,0 +1,36 @@
+package org.rundeck.api.domain;
+
+/**
+ * RundeckToken is ...
+ *
+ * @author Greg Schueler
+ * @since 2014-04-04
+ */
+public class RundeckToken {
+ private String user;
+ private String token;
+
+ public RundeckToken() {
+ }
+
+ public RundeckToken(String user, String token) {
+ this.setUser(user);
+ this.setToken(token);
+ }
+
+ public String getUser() {
+ return user;
+ }
+
+ public void setUser(String user) {
+ this.user = user;
+ }
+
+ public String getToken() {
+ return token;
+ }
+
+ public void setToken(String token) {
+ this.token = token;
+ }
+}
diff --git a/src/main/java/org/rundeck/api/parser/RundeckTokenParser.java b/src/main/java/org/rundeck/api/parser/RundeckTokenParser.java
new file mode 100644
index 0000000..b48543d
--- /dev/null
+++ b/src/main/java/org/rundeck/api/parser/RundeckTokenParser.java
@@ -0,0 +1,33 @@
+package org.rundeck.api.parser;
+
+import org.dom4j.Node;
+import org.rundeck.api.domain.RundeckToken;
+
+/**
+ * RundeckTokenParser is ...
+ *
+ * @author Greg Schueler
+ * @since 2014-04-04
+ */
+public class RundeckTokenParser implements XmlNodeParser {
+ String xpath;
+
+ public RundeckTokenParser() {
+ }
+
+ public RundeckTokenParser(String xpath) {
+ this.xpath = xpath;
+ }
+
+ @Override
+ public RundeckToken parseXmlNode(Node node) {
+ Node targetNode = xpath != null ? node.selectSingleNode(xpath) : node;
+ RundeckToken rundeckToken = new RundeckToken();
+ String token = targetNode.valueOf("@id");
+ String user = targetNode.valueOf("@user");
+ rundeckToken.setToken(token);
+ rundeckToken.setUser(user);
+
+ return rundeckToken;
+ }
+}
diff --git a/src/test/java/org/rundeck/api/RundeckClientTest.java b/src/test/java/org/rundeck/api/RundeckClientTest.java
index f0aa4b6..053ff51 100644
--- a/src/test/java/org/rundeck/api/RundeckClientTest.java
+++ b/src/test/java/org/rundeck/api/RundeckClientTest.java
@@ -55,6 +55,7 @@ public class RundeckClientTest {
public static final String TEST_TOKEN_4 = "sN5RRSNvu15DnV6EcNDdc2CkdPcv3s32";
public static final String TEST_TOKEN_5 = "C3O6d5O98Kr6Dpv71sdE4ERdCuU12P6d";
public static final String TEST_TOKEN_6 = "Do4d3NUD5DKk21DR4sNK755RcPk618vn";
+ public static final String TEST_TOKEN_7 = "8Dp9op111ER6opsDRkddvE86K9sE499s";
@Rule
public Recorder recorder = new Recorder();
@@ -1197,6 +1198,89 @@ public class RundeckClientTest {
Assert.assertEquals(RundeckWFExecState.SUCCEEDED,output.getExecutionState());
}
+ /**
+ * generate api token
+ */
+ @Test
+ @Betamax(tape = "api_token_generate", mode = TapeMode.READ_ONLY)
+ public void generateApiToken() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_7, 11);
+ String token = client.generateApiToken("bob");
+
+ Assert.assertNotNull(token);
+ Assert.assertEquals("MiquQjELTrEaugpmdgAKs1W3a7xonAwU", token);
+ }
+ /**
+ * get api token
+ */
+ @Test
+ @Betamax(tape = "api_token_get", mode = TapeMode.READ_ONLY)
+ public void getApiToken() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_7, 11);
+ RundeckToken token = client.getApiToken("MiquQjELTrEaugpmdgAKs1W3a7xonAwU");
+
+ Assert.assertNotNull(token);
+ Assert.assertEquals("MiquQjELTrEaugpmdgAKs1W3a7xonAwU", token.getToken());
+ Assert.assertEquals("bob", token.getUser());
+ }
+ /**
+ * list api tokens for user
+ */
+ @Test
+ @Betamax(tape = "api_tokens_list_user", mode = TapeMode.READ_ONLY)
+ public void listApiTokens_user() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_7, 11);
+ List tokens = client.listApiTokens("bob");
+
+ Assert.assertNotNull(tokens);
+ Assert.assertEquals(3, tokens.size());
+ Assert.assertEquals("hINp5eGzvYA9UePbUChaKHd5NiRkwWbx", tokens.get(0).getToken());
+ Assert.assertEquals("bob", tokens.get(0).getUser());
+ Assert.assertEquals("NaNnwVzAHAG83qOS7Wtwh6mjcXViyWUV", tokens.get(1).getToken());
+ Assert.assertEquals("bob", tokens.get(1).getUser());
+ Assert.assertEquals("MiquQjELTrEaugpmdgAKs1W3a7xonAwU", tokens.get(2).getToken());
+ Assert.assertEquals("bob", tokens.get(2).getUser());
+ }
+ /**
+ * list api tokens all
+ */
+ @Test
+ @Betamax(tape = "api_tokens_list_all"/*, mode = TapeMode.READ_ONLY*/)
+ public void listApiTokens() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_7, 11);
+ List tokens = client.listApiTokens();
+
+ Assert.assertNotNull(tokens);
+ Assert.assertEquals(4, tokens.size());
+ Assert.assertEquals("8Dp9op111ER6opsDRkddvE86K9sE499s", tokens.get(0).getToken());
+ Assert.assertEquals("admin", tokens.get(0).getUser());
+ Assert.assertEquals("hINp5eGzvYA9UePbUChaKHd5NiRkwWbx", tokens.get(1).getToken());
+ Assert.assertEquals("bob", tokens.get(1).getUser());
+ Assert.assertEquals("NaNnwVzAHAG83qOS7Wtwh6mjcXViyWUV", tokens.get(2).getToken());
+ Assert.assertEquals("bob", tokens.get(2).getUser());
+ Assert.assertEquals("MiquQjELTrEaugpmdgAKs1W3a7xonAwU", tokens.get(3).getToken());
+ Assert.assertEquals("bob", tokens.get(3).getUser());
+ }
+
+ /**
+ * get api token
+ */
+ @Test
+ @Betamax(tape = "api_token_delete"/*, mode = TapeMode.READ_ONLY*/)
+ public void deleteApiToken() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_7, 11);
+
+ client.deleteApiToken("MiquQjELTrEaugpmdgAKs1W3a7xonAwU");
+
+ //get should now return 404
+ try {
+ client.getApiToken("MiquQjELTrEaugpmdgAKs1W3a7xonAwU");
+ Assert.fail("expected failure");
+ } catch (RundeckApiException.RundeckApiHttpStatusException e) {
+ Assert.assertEquals(404, e.getStatusCode());
+ }
+ }
+
@Before
public void setUp() throws Exception {
// not that you can put whatever here, because we don't actually connect to the RunDeck instance
diff --git a/src/test/resources/betamax/tapes/api_token_delete.yaml b/src/test/resources/betamax/tapes/api_token_delete.yaml
new file mode 100644
index 0000000..92fc6c0
--- /dev/null
+++ b/src/test/resources/betamax/tapes/api_token_delete.yaml
@@ -0,0 +1,36 @@
+!tape
+name: api_token_delete
+interactions:
+- recorded: 2014-04-04T18:38:18.432Z
+ request:
+ method: DELETE
+ uri: http://rundeck.local:4440/api/11/token/MiquQjELTrEaugpmdgAKs1W3a7xonAwU
+ headers:
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
+ response:
+ status: 204
+ headers:
+ Content-Type: text/html;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=j0fidhqqsmlt1qmvaawr52a42;Path=/
+- recorded: 2014-04-04T18:38:18.523Z
+ request:
+ method: GET
+ uri: http://rundeck.local:4440/api/11/token/MiquQjELTrEaugpmdgAKs1W3a7xonAwU
+ headers:
+ Accept: text/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
+ response:
+ status: 404
+ headers:
+ Content-Type: text/xml;charset=UTF-8
+ Server: Jetty(7.6.0.v20120127)
+ X-Rundeck-API-Version: '11'
+ body: "\n \n Token does not exist: MiquQjELTrEaugpmdgAKs1W3a7xonAwU \n \n "
diff --git a/src/test/resources/betamax/tapes/api_token_generate.yaml b/src/test/resources/betamax/tapes/api_token_generate.yaml
new file mode 100644
index 0000000..1a5f72d
--- /dev/null
+++ b/src/test/resources/betamax/tapes/api_token_generate.yaml
@@ -0,0 +1,25 @@
+!tape
+name: api_token_generate
+interactions:
+- recorded: 2014-04-04T18:21:07.759Z
+ request:
+ method: POST
+ uri: http://rundeck.local:4440/api/11/tokens/bob
+ headers:
+ Accept: text/xml
+ Content-Length: '0'
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
+ response:
+ status: 201
+ headers:
+ Content-Type: application/xml;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=1gt9t2gch2zff1a0werz1us5wk;Path=/
+ X-Rundeck-API-Version: '11'
+ X-Rundeck-API-XML-Response-Wrapper: 'false'
+ body: !!binary |-
+ PHRva2VuIGlkPSdNaXF1UWpFTFRyRWF1Z3BtZGdBS3MxVzNhN3hvbkF3VScgdXNlcj0nYm9iJyAvPg==
diff --git a/src/test/resources/betamax/tapes/api_token_get.yaml b/src/test/resources/betamax/tapes/api_token_get.yaml
new file mode 100644
index 0000000..8377d6f
--- /dev/null
+++ b/src/test/resources/betamax/tapes/api_token_get.yaml
@@ -0,0 +1,24 @@
+!tape
+name: api_token_get
+interactions:
+- recorded: 2014-04-04T18:23:05.986Z
+ request:
+ method: GET
+ uri: http://rundeck.local:4440/api/11/token/MiquQjELTrEaugpmdgAKs1W3a7xonAwU
+ headers:
+ Accept: text/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
+ response:
+ status: 200
+ headers:
+ Content-Type: application/xml;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=1tdpszk6b3v191p0ng2u94rohw;Path=/
+ X-Rundeck-API-Version: '11'
+ X-Rundeck-API-XML-Response-Wrapper: 'false'
+ body: !!binary |-
+ PHRva2VuIGlkPSdNaXF1UWpFTFRyRWF1Z3BtZGdBS3MxVzNhN3hvbkF3VScgdXNlcj0nYm9iJyAvPg==
diff --git a/src/test/resources/betamax/tapes/api_tokens_list_all.yaml b/src/test/resources/betamax/tapes/api_tokens_list_all.yaml
new file mode 100644
index 0000000..f1318ad
--- /dev/null
+++ b/src/test/resources/betamax/tapes/api_tokens_list_all.yaml
@@ -0,0 +1,24 @@
+!tape
+name: api_tokens_list_all
+interactions:
+- recorded: 2014-04-04T18:32:37.397Z
+ request:
+ method: GET
+ uri: http://rundeck.local:4440/api/11/tokens
+ headers:
+ Accept: text/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
+ response:
+ status: 200
+ headers:
+ Content-Type: application/xml;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=ixag173yjktz1c5o9yrbe5z5a;Path=/
+ X-Rundeck-API-Version: '11'
+ X-Rundeck-API-XML-Response-Wrapper: 'false'
+ body: !!binary |-
+ PHRva2VucyBjb3VudD0nNCcgYWxsdXNlcnM9J3RydWUnPgogIDx0b2tlbiBpZD0nOERwOW9wMTExRVI2b3BzRFJrZGR2RTg2SzlzRTQ5OXMnIHVzZXI9J2FkbWluJyAvPgogIDx0b2tlbiBpZD0naElOcDVlR3p2WUE5VWVQYlVDaGFLSGQ1TmlSa3dXYngnIHVzZXI9J2JvYicgLz4KICA8dG9rZW4gaWQ9J05hTm53VnpBSEFHODNxT1M3V3R3aDZtamNYVml5V1VWJyB1c2VyPSdib2InIC8+CiAgPHRva2VuIGlkPSdNaXF1UWpFTFRyRWF1Z3BtZGdBS3MxVzNhN3hvbkF3VScgdXNlcj0nYm9iJyAvPgo8L3Rva2Vucz4=
diff --git a/src/test/resources/betamax/tapes/api_tokens_list_user.yaml b/src/test/resources/betamax/tapes/api_tokens_list_user.yaml
new file mode 100644
index 0000000..15ec26d
--- /dev/null
+++ b/src/test/resources/betamax/tapes/api_tokens_list_user.yaml
@@ -0,0 +1,24 @@
+!tape
+name: api_tokens_list_user
+interactions:
+- recorded: 2014-04-04T18:26:33.394Z
+ request:
+ method: GET
+ uri: http://rundeck.local:4440/api/11/tokens/bob
+ headers:
+ Accept: text/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
+ response:
+ status: 200
+ headers:
+ Content-Type: application/xml;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=114794elwavo26cx4ugkv7pe7;Path=/
+ X-Rundeck-API-Version: '11'
+ X-Rundeck-API-XML-Response-Wrapper: 'false'
+ body: !!binary |-
+ PHRva2VucyBjb3VudD0nMycgdXNlcj0nYm9iJz4KICA8dG9rZW4gaWQ9J2hJTnA1ZUd6dllBOVVlUGJVQ2hhS0hkNU5pUmt3V2J4JyB1c2VyPSdib2InIC8+CiAgPHRva2VuIGlkPSdOYU5ud1Z6QUhBRzgzcU9TN1d0d2g2bWpjWFZpeVdVVicgdXNlcj0nYm9iJyAvPgogIDx0b2tlbiBpZD0nTWlxdVFqRUxUckVhdWdwbWRnQUtzMVczYTd4b25Bd1UnIHVzZXI9J2JvYicgLz4KPC90b2tlbnM+
From c7153a5613156d253901babd52dc4f891cbb306c Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Fri, 4 Apr 2014 11:42:29 -0700
Subject: [PATCH 51/89] API token support added (api v11)
---
src/site/confluence/status.confluence | 6 +++---
src/test/java/org/rundeck/api/RundeckClientTest.java | 4 ++--
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/site/confluence/status.confluence b/src/site/confluence/status.confluence
index 9bc64f9..0dfbb3e 100644
--- a/src/site/confluence/status.confluence
+++ b/src/site/confluence/status.confluence
@@ -110,6 +110,6 @@ h2. RunDeck API version 11
* SSH Key delete - *TODO*
* SSH Key list - *TODO*
* SSH Key get - *TODO*
-* API Token create - *TODO*
-* API Token list - *TODO*
-* API Token delete - *TODO*
+* API Token create - OK
+* API Token list - OK
+* API Token delete - OK
diff --git a/src/test/java/org/rundeck/api/RundeckClientTest.java b/src/test/java/org/rundeck/api/RundeckClientTest.java
index 053ff51..654334d 100644
--- a/src/test/java/org/rundeck/api/RundeckClientTest.java
+++ b/src/test/java/org/rundeck/api/RundeckClientTest.java
@@ -1245,7 +1245,7 @@ public class RundeckClientTest {
* list api tokens all
*/
@Test
- @Betamax(tape = "api_tokens_list_all"/*, mode = TapeMode.READ_ONLY*/)
+ @Betamax(tape = "api_tokens_list_all", mode = TapeMode.READ_ONLY)
public void listApiTokens() throws Exception {
final RundeckClient client = createClient(TEST_TOKEN_7, 11);
List tokens = client.listApiTokens();
@@ -1266,7 +1266,7 @@ public class RundeckClientTest {
* get api token
*/
@Test
- @Betamax(tape = "api_token_delete"/*, mode = TapeMode.READ_ONLY*/)
+ @Betamax(tape = "api_token_delete", mode = TapeMode.READ_ONLY)
public void deleteApiToken() throws Exception {
final RundeckClient client = createClient(TEST_TOKEN_7, 11);
From 459b498d35a5e6ec52c90f8ea59659ece498d27c Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Fri, 4 Apr 2014 13:47:01 -0700
Subject: [PATCH 52/89] Add support for SSH key management (api v11)
---
src/main/java/org/rundeck/api/ApiCall.java | 57 ++++-
.../java/org/rundeck/api/ApiPathBuilder.java | 11 +
.../org/rundeck/api/RundeckApiException.java | 38 ++++
.../java/org/rundeck/api/RundeckClient.java | 137 +++++++++++-
.../api/domain/BaseSSHKeyResource.java | 61 +++++
.../api/domain/BaseStorageResource.java | 86 +++++++
.../rundeck/api/domain/SSHKeyResource.java | 23 ++
.../rundeck/api/domain/StorageResource.java | 54 +++++
.../rundeck/api/parser/BaseXpathParser.java | 29 +++
.../api/parser/SSHKeyResourceParser.java | 26 +++
.../api/parser/StorageResourceParser.java | 61 +++++
.../org/rundeck/api/RundeckClientTest.java | 209 ++++++++++++++++++
.../betamax/tapes/ssh_key_delete.yaml | 36 +++
.../tapes/ssh_key_get_data_private.yaml | 22 ++
.../tapes/ssh_key_get_data_public.yaml | 22 ++
.../betamax/tapes/ssh_key_get_private.yaml | 22 ++
.../betamax/tapes/ssh_key_get_public.yaml | 22 ++
.../betamax/tapes/ssh_key_list_directory.yaml | 21 ++
.../betamax/tapes/ssh_key_list_root.yaml | 21 ++
.../betamax/tapes/ssh_key_store_private.yaml | 25 +++
.../betamax/tapes/ssh_key_store_public.yaml | 25 +++
21 files changed, 1002 insertions(+), 6 deletions(-)
create mode 100644 src/main/java/org/rundeck/api/domain/BaseSSHKeyResource.java
create mode 100644 src/main/java/org/rundeck/api/domain/BaseStorageResource.java
create mode 100644 src/main/java/org/rundeck/api/domain/SSHKeyResource.java
create mode 100644 src/main/java/org/rundeck/api/domain/StorageResource.java
create mode 100644 src/main/java/org/rundeck/api/parser/BaseXpathParser.java
create mode 100644 src/main/java/org/rundeck/api/parser/SSHKeyResourceParser.java
create mode 100644 src/main/java/org/rundeck/api/parser/StorageResourceParser.java
create mode 100644 src/test/resources/betamax/tapes/ssh_key_delete.yaml
create mode 100644 src/test/resources/betamax/tapes/ssh_key_get_data_private.yaml
create mode 100644 src/test/resources/betamax/tapes/ssh_key_get_data_public.yaml
create mode 100644 src/test/resources/betamax/tapes/ssh_key_get_private.yaml
create mode 100644 src/test/resources/betamax/tapes/ssh_key_get_public.yaml
create mode 100644 src/test/resources/betamax/tapes/ssh_key_list_directory.yaml
create mode 100644 src/test/resources/betamax/tapes/ssh_key_list_root.yaml
create mode 100644 src/test/resources/betamax/tapes/ssh_key_store_private.yaml
create mode 100644 src/test/resources/betamax/tapes/ssh_key_store_public.yaml
diff --git a/src/main/java/org/rundeck/api/ApiCall.java b/src/main/java/org/rundeck/api/ApiCall.java
index 07e09f9..71a9808 100644
--- a/src/main/java/org/rundeck/api/ApiCall.java
+++ b/src/main/java/org/rundeck/api/ApiCall.java
@@ -387,10 +387,14 @@ class ApiCall {
if (null != apiPath.getAccept()) {
request.setHeader("Accept", apiPath.getAccept());
}
- WriteOutHandler handler = new WriteOutHandler(outputStream);
- int wrote = execute(request, handler);
- if(handler.thrown!=null){
- throw handler.thrown;
+ final WriteOutHandler writeOutHandler = new WriteOutHandler(outputStream);
+ Handler handler = writeOutHandler;
+ if(null!=apiPath.getRequiredContentType()){
+ handler = new RequireContentTypeHandler(apiPath.getRequiredContentType(), handler);
+ }
+ final int wrote = execute(request, handler);
+ if(writeOutHandler.thrown!=null){
+ throw writeOutHandler.thrown;
}
return wrote;
}
@@ -435,6 +439,51 @@ class ApiCall {
}
}
+ /**
+ * Handles writing response to an output stream
+ */
+ private static class ChainHandler implements Handler {
+ Handler chain;
+ private ChainHandler(Handler chain) {
+ this.chain=chain;
+ }
+ @Override
+ public T handle(final HttpResponse response) {
+ return chain.handle(response);
+ }
+ }
+
+ /**
+ * Handles writing response to an output stream
+ */
+ private static class RequireContentTypeHandler extends ChainHandler {
+ String contentType;
+
+ private RequireContentTypeHandler(final String contentType, final Handler chain) {
+ super(chain);
+ this.contentType = contentType;
+ }
+
+ @Override
+ public T handle(final HttpResponse response) {
+ final Header firstHeader = response.getFirstHeader("Content-Type");
+ final String[] split = firstHeader.getValue().split(";");
+ boolean matched=false;
+ for (int i = 0; i < split.length; i++) {
+ String s = split[i];
+ if (this.contentType.equalsIgnoreCase(s.trim())) {
+ matched=true;
+ break;
+ }
+ }
+ if(!matched) {
+ throw new RundeckApiException.RundeckApiHttpContentTypeException(firstHeader.getValue(),
+ this.contentType);
+ }
+ return super.handle(response);
+ }
+ }
+
/**
* Handles writing response to an output stream
*/
diff --git a/src/main/java/org/rundeck/api/ApiPathBuilder.java b/src/main/java/org/rundeck/api/ApiPathBuilder.java
index 05250ec..7ef79ee 100644
--- a/src/main/java/org/rundeck/api/ApiPathBuilder.java
+++ b/src/main/java/org/rundeck/api/ApiPathBuilder.java
@@ -50,6 +50,7 @@ class ApiPathBuilder {
private InputStream contentStream;
private File contentFile;
private String contentType;
+ private String requiredContentType;
private boolean emptyContent = false;
/** Marker for using the right separator between parameters ("?" or "&") */
@@ -416,6 +417,16 @@ class ApiPathBuilder {
public boolean isEmptyContent() {
return emptyContent;
}
+
+ public ApiPathBuilder requireContentType(String contentType) {
+ this.requiredContentType=contentType;
+ return this;
+ }
+
+ public String getRequiredContentType() {
+ return requiredContentType;
+ }
+
/**
* BuildsParameters can add URL or POST parameters to an {@link ApiPathBuilder}
*
diff --git a/src/main/java/org/rundeck/api/RundeckApiException.java b/src/main/java/org/rundeck/api/RundeckApiException.java
index 2a5b1ca..5a2de8b 100644
--- a/src/main/java/org/rundeck/api/RundeckApiException.java
+++ b/src/main/java/org/rundeck/api/RundeckApiException.java
@@ -105,4 +105,42 @@ public class RundeckApiException extends RuntimeException {
}
}
+ /**
+ * Error due to unexpected HTTP content-type
+ */
+ public static class RundeckApiHttpContentTypeException extends RundeckApiAuthException {
+
+ private static final long serialVersionUID = 1L;
+ private String contentType;
+ private String requiredContentType;
+
+ public RundeckApiHttpContentTypeException(final String contentType,
+ final String requiredContentType) {
+ super("Unexpected content-type: '" + contentType + "', expected: '" + requiredContentType + "'");
+ this.contentType = contentType;
+ this.requiredContentType = requiredContentType;
+ }
+ public RundeckApiHttpContentTypeException(final String message, final String contentType,
+ final String requiredContentType) {
+ super(message);
+ this.contentType = contentType;
+ this.requiredContentType = requiredContentType;
+ }
+
+ public RundeckApiHttpContentTypeException(final String message, final Throwable cause, final String contentType,
+ final String requiredContentType) {
+ super(message, cause);
+ this.contentType = contentType;
+ this.requiredContentType = requiredContentType;
+ }
+
+ public String getContentType() {
+ return contentType;
+ }
+
+ public String getRequiredContentType() {
+ return requiredContentType;
+ }
+ }
+
}
diff --git a/src/main/java/org/rundeck/api/RundeckClient.java b/src/main/java/org/rundeck/api/RundeckClient.java
index e56bda1..b0baa4c 100644
--- a/src/main/java/org/rundeck/api/RundeckClient.java
+++ b/src/main/java/org/rundeck/api/RundeckClient.java
@@ -19,8 +19,6 @@ import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
-import org.dom4j.DocumentFactory;
-import org.dom4j.Element;
import org.rundeck.api.RundeckApiException.RundeckApiLoginException;
import org.rundeck.api.RundeckApiException.RundeckApiTokenException;
import org.rundeck.api.domain.*;
@@ -83,6 +81,8 @@ public class RundeckClient implements Serializable {
private static final long serialVersionUID = 1L;
public static final String JOBS_IMPORT = "/jobs/import";
+ public static final String STORAGE_ROOT_PATH = "/storage/";
+ public static final String SSH_KEY_PATH = "ssh-key/";
/**
* Supported version numbers
@@ -2374,6 +2374,139 @@ public class RundeckClient implements Serializable {
return new ApiCall(this).get(new ApiPathBuilder("/token/", token), new RundeckTokenParser("/token"));
}
+ /**
+ * Store an SSH key file
+ * @param path ssh key storage path, must start with "ssh-key/"
+ * @param keyfile key file
+ * @param privateKey true to store private key, false to store public key
+ * @return the SSH key resource
+ * @throws RundeckApiException
+ */
+ public SSHKeyResource storeSshKey(final String path, final File keyfile, boolean privateKey) throws RundeckApiException{
+ AssertUtil.notNull(path, "path is mandatory to store an SSH key.");
+ AssertUtil.notNull(keyfile, "keyfile is mandatory to store an SSH key.");
+ if (!path.startsWith(SSH_KEY_PATH)) {
+ throw new IllegalArgumentException("SSH key storage path must start with: " + SSH_KEY_PATH);
+ }
+ return new ApiCall(this).post(
+ new ApiPathBuilder(STORAGE_ROOT_PATH, path).content(
+ privateKey ? "application/octet-stream" : "application/pgp-keys",
+ keyfile
+ ),
+ new SSHKeyResourceParser("/resource")
+ );
+ }
+
+ /**
+ * Get metadata for an SSH key file
+ *
+ * @param path ssh key storage path, must start with "ssh-key/"
+ *
+ * @return the ssh key resource
+ *
+ * @throws RundeckApiException if there is an error, or if the path is a directory not a file
+ */
+ public SSHKeyResource getSshKey(final String path) throws RundeckApiException {
+ AssertUtil.notNull(path, "path is mandatory to get an SSH key.");
+ if (!path.startsWith(SSH_KEY_PATH)) {
+ throw new IllegalArgumentException("SSH key storage path must start with: " + SSH_KEY_PATH);
+ }
+ SSHKeyResource storageResource = new ApiCall(this).get(
+ new ApiPathBuilder(STORAGE_ROOT_PATH, path),
+ new SSHKeyResourceParser("/resource")
+ );
+ if (storageResource.isDirectory()) {
+ throw new RundeckApiException("SSH Key Path is a directory: " + path);
+ }
+ return storageResource;
+ }
+
+ /**
+ * Get content for a public SSH key file
+ * @param path ssh key storage path, must start with "ssh-key/"
+ * @param out outputstream to write data to
+ *
+ * @return length of written data
+ * @throws RundeckApiException
+ */
+ public int getPublicSshKeyContent(final String path, final OutputStream out) throws
+ RundeckApiException, IOException {
+ AssertUtil.notNull(path, "path is mandatory to get an SSH key.");
+ if (!path.startsWith(SSH_KEY_PATH)) {
+ throw new IllegalArgumentException("SSH key storage path must start with: " + SSH_KEY_PATH);
+ }
+ try {
+ return new ApiCall(this).get(
+ new ApiPathBuilder(STORAGE_ROOT_PATH, path)
+ .accept("application/pgp-keys")
+ .requireContentType("application/pgp-keys"),
+ out
+ );
+ } catch (RundeckApiException.RundeckApiHttpContentTypeException e) {
+ throw new RundeckApiException("Requested SSH Key path was not a Public key: " + path, e);
+ }
+ }
+
+ /**
+ * Get content for a public SSH key file
+ * @param path ssh key storage path, must start with "ssh-key/"
+ * @param out file to write data to
+ * @return length of written data
+ * @throws RundeckApiException
+ */
+ public int getPublicSshKeyContent(final String path, final File out) throws
+ RundeckApiException, IOException {
+ final FileOutputStream fileOutputStream = new FileOutputStream(out);
+ try {
+ return getPublicSshKeyContent(path, fileOutputStream);
+ }finally {
+ fileOutputStream.close();
+ }
+ }
+
+ /**
+ * List contents of root SSH key directory
+ *
+ * @return list of SSH key resources
+ * @throws RundeckApiException
+ */
+ public List listSshKeyDirectoryRoot() throws RundeckApiException {
+ return listSshKeyDirectory(SSH_KEY_PATH);
+ }
+ /**
+ * List contents of SSH key directory
+ *
+ * @param path ssh key storage path, must start with "ssh-key/"
+ *
+ * @throws RundeckApiException if there is an error, or if the path is a file not a directory
+ */
+ public List listSshKeyDirectory(final String path) throws RundeckApiException {
+ AssertUtil.notNull(path, "path is mandatory to get an SSH key.");
+ if (!path.startsWith(SSH_KEY_PATH)) {
+ throw new IllegalArgumentException("SSH key storage path must start with: " + SSH_KEY_PATH);
+ }
+ SSHKeyResource storageResource = new ApiCall(this).get(
+ new ApiPathBuilder(STORAGE_ROOT_PATH, path),
+ new SSHKeyResourceParser("/resource")
+ );
+ if(!storageResource.isDirectory()) {
+ throw new RundeckApiException("SSH key path is not a directory path: " + path);
+ }
+ return storageResource.getDirectoryContents();
+ }
+
+ /**
+ * Delete an SSH key file
+ * @param path a path to a SSH key file, must start with "ssh-key/"
+ */
+ public void deleteSshKey(final String path){
+ AssertUtil.notNull(path, "path is mandatory to delete an SSH key.");
+ if (!path.startsWith(SSH_KEY_PATH)) {
+ throw new IllegalArgumentException("SSH key storage path must start with: " + SSH_KEY_PATH);
+ }
+ new ApiCall(this).delete(new ApiPathBuilder(STORAGE_ROOT_PATH, path));
+ }
+
/**
* @return the URL of the RunDeck instance ("http://localhost:4440", "http://rundeck.your-compagny.com/", etc)
*/
diff --git a/src/main/java/org/rundeck/api/domain/BaseSSHKeyResource.java b/src/main/java/org/rundeck/api/domain/BaseSSHKeyResource.java
new file mode 100644
index 0000000..b47d878
--- /dev/null
+++ b/src/main/java/org/rundeck/api/domain/BaseSSHKeyResource.java
@@ -0,0 +1,61 @@
+package org.rundeck.api.domain;
+
+import org.rundeck.api.RundeckClient;
+import org.rundeck.api.parser.StorageResourceParser;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * BaseSSHKeyResource is ...
+ *
+ * @author Greg Schueler
+ * @since 2014-04-04
+ */
+public class BaseSSHKeyResource extends BaseStorageResource implements SSHKeyResource {
+ private boolean privateKey;
+
+ public BaseSSHKeyResource() {
+ }
+
+
+ public boolean isPrivateKey() {
+ return privateKey;
+ }
+
+ public void setPrivateKey(boolean privateKey) {
+ this.privateKey = privateKey;
+ }
+
+ ArrayList sshKeyResources = new ArrayList();
+
+ @Override
+ public void setDirectoryContents(List extends StorageResource> directoryContents) {
+ for (StorageResource directoryContent : directoryContents) {
+ sshKeyResources.add(from(directoryContent));
+ }
+ }
+
+ @Override
+ public List getDirectoryContents() {
+ return sshKeyResources;
+ }
+
+ public static BaseSSHKeyResource from(final StorageResource source) {
+ final BaseSSHKeyResource baseSshKeyResource = new BaseSSHKeyResource();
+ baseSshKeyResource.setDirectory(source.isDirectory());
+ baseSshKeyResource.setPath(source.getPath());
+ baseSshKeyResource.setName(source.getName());
+ baseSshKeyResource.setMetadata(source.getMetadata());
+ baseSshKeyResource.setUrl(source.getUrl());
+ if (!baseSshKeyResource.isDirectory()) {
+ baseSshKeyResource.setPrivateKey(
+ null != baseSshKeyResource.getMetadata() && "private".equals(baseSshKeyResource.getMetadata().get
+ ("Rundeck-ssh-key-type"))
+ );
+ } else if (null != source.getDirectoryContents()) {
+ baseSshKeyResource.setDirectoryContents(source.getDirectoryContents());
+ }
+ return baseSshKeyResource;
+ }
+}
diff --git a/src/main/java/org/rundeck/api/domain/BaseStorageResource.java b/src/main/java/org/rundeck/api/domain/BaseStorageResource.java
new file mode 100644
index 0000000..6639ab4
--- /dev/null
+++ b/src/main/java/org/rundeck/api/domain/BaseStorageResource.java
@@ -0,0 +1,86 @@
+package org.rundeck.api.domain;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * BaseStorageResource is ...
+ *
+ * @author Greg Schueler
+ * @since 2014-04-04
+ */
+public class BaseStorageResource implements StorageResource {
+ private String path;
+ private String url;
+ private String name;
+ private Map metadata;
+ private boolean directory;
+ private List extends StorageResource> directoryContents;
+
+ public BaseStorageResource() {
+ }
+
+ @Override
+ public String getPath() {
+ return path;
+ }
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ @Override
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public Map getMetadata() {
+ return metadata;
+ }
+
+ public void setMetadata(Map metadata) {
+ this.metadata = metadata;
+ }
+
+ @Override
+ public boolean isDirectory() {
+ return directory;
+ }
+
+ public void setDirectory(boolean directory) {
+ this.directory = directory;
+ }
+
+ @Override
+ public List extends StorageResource> getDirectoryContents() {
+ return directoryContents;
+ }
+
+ public void setDirectoryContents(List extends StorageResource> directoryContents) {
+ this.directoryContents = directoryContents;
+ }
+
+ @Override
+ public String toString() {
+ return "BaseStorageResource{" +
+ "path='" + path + '\'' +
+ ", url='" + url + '\'' +
+ ", name='" + name + '\'' +
+ ", directory=" + directory +
+ '}';
+ }
+}
diff --git a/src/main/java/org/rundeck/api/domain/SSHKeyResource.java b/src/main/java/org/rundeck/api/domain/SSHKeyResource.java
new file mode 100644
index 0000000..33bbbd5
--- /dev/null
+++ b/src/main/java/org/rundeck/api/domain/SSHKeyResource.java
@@ -0,0 +1,23 @@
+package org.rundeck.api.domain;
+
+import java.util.List;
+
+/**
+ * SSHKeyResource represents a directory or an SSH key file
+ *
+ * @author Greg Schueler
+ * @since 2014-04-04
+ */
+public interface SSHKeyResource extends StorageResource {
+ /**
+ * Return true if this is a file and is a private SSH key file.
+ * @return
+ */
+ public boolean isPrivateKey();
+
+ /**
+ * Return the list of SSH Key resources if this is a directory
+ * @return
+ */
+ public List getDirectoryContents();
+}
diff --git a/src/main/java/org/rundeck/api/domain/StorageResource.java b/src/main/java/org/rundeck/api/domain/StorageResource.java
new file mode 100644
index 0000000..be02412
--- /dev/null
+++ b/src/main/java/org/rundeck/api/domain/StorageResource.java
@@ -0,0 +1,54 @@
+package org.rundeck.api.domain;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * StorageResource represents a directory or a file
+ *
+ * @author Greg Schueler
+ * @since 2014-04-04
+ */
+public interface StorageResource {
+ /**
+ * Return the storage path for this resource
+ *
+ * @return
+ */
+ public String getPath();
+
+ /**
+ * Return the URL for this resource
+ *
+ * @return
+ */
+ public String getUrl();
+
+ /**
+ * Return the file name if this is a file
+ *
+ * @return
+ */
+ public String getName();
+
+ /**
+ * Return the metadata for this file if this is a file
+ *
+ * @return
+ */
+ public Map getMetadata();
+
+ /**
+ * Return true if this is a directory, false if this is a file
+ *
+ * @return
+ */
+ public boolean isDirectory();
+
+ /**
+ * Return the list of directory contents if this is a directory
+ *
+ * @return
+ */
+ public List extends StorageResource> getDirectoryContents();
+}
diff --git a/src/main/java/org/rundeck/api/parser/BaseXpathParser.java b/src/main/java/org/rundeck/api/parser/BaseXpathParser.java
new file mode 100644
index 0000000..26be541
--- /dev/null
+++ b/src/main/java/org/rundeck/api/parser/BaseXpathParser.java
@@ -0,0 +1,29 @@
+package org.rundeck.api.parser;
+
+import org.dom4j.Node;
+
+/**
+ * BaseXpathParser is ...
+ *
+ * @author Greg Schueler
+ * @since 2014-04-04
+ */
+public abstract class BaseXpathParser implements XmlNodeParser {
+ private String xpath;
+
+ public BaseXpathParser() {
+ }
+
+ public BaseXpathParser(String xpath) {
+
+ this.xpath = xpath;
+ }
+
+ public abstract T parse(Node node);
+
+ @Override
+ public T parseXmlNode(Node node) {
+ Node selectedNode = xpath != null ? node.selectSingleNode(xpath) : node;
+ return parse(selectedNode);
+ }
+}
diff --git a/src/main/java/org/rundeck/api/parser/SSHKeyResourceParser.java b/src/main/java/org/rundeck/api/parser/SSHKeyResourceParser.java
new file mode 100644
index 0000000..5485d31
--- /dev/null
+++ b/src/main/java/org/rundeck/api/parser/SSHKeyResourceParser.java
@@ -0,0 +1,26 @@
+package org.rundeck.api.parser;
+
+import org.dom4j.Node;
+import org.rundeck.api.RundeckClient;
+import org.rundeck.api.domain.BaseSSHKeyResource;
+import org.rundeck.api.domain.SSHKeyResource;
+
+/**
+ * SSHKeyResourceParser is ...
+ *
+ * @author Greg Schueler
+ * @since 2014-04-04
+ */
+public class SSHKeyResourceParser extends BaseXpathParser implements XmlNodeParser {
+ public SSHKeyResourceParser() {
+ }
+
+ public SSHKeyResourceParser(String xpath) {
+ super(xpath);
+ }
+
+ @Override
+ public SSHKeyResource parse(Node node) {
+ return BaseSSHKeyResource.from(new StorageResourceParser().parse(node));
+ }
+}
diff --git a/src/main/java/org/rundeck/api/parser/StorageResourceParser.java b/src/main/java/org/rundeck/api/parser/StorageResourceParser.java
new file mode 100644
index 0000000..f1c5e6a
--- /dev/null
+++ b/src/main/java/org/rundeck/api/parser/StorageResourceParser.java
@@ -0,0 +1,61 @@
+package org.rundeck.api.parser;
+
+import org.dom4j.Element;
+import org.dom4j.Node;
+import org.rundeck.api.domain.BaseStorageResource;
+import org.rundeck.api.domain.StorageResource;
+
+import java.util.HashMap;
+
+/**
+ * StorageResourceParser is ...
+ *
+ * @author Greg Schueler
+ * @since 2014-04-04
+ */
+public class StorageResourceParser extends BaseXpathParser {
+ private BaseStorageResource holder;
+ public StorageResourceParser() {
+
+ }
+ public StorageResourceParser(BaseStorageResource holder){
+ this.holder=holder;
+ }
+
+ public StorageResourceParser(String xpath) {
+ super(xpath);
+ }
+
+ @Override
+ public StorageResource parse(Node node) {
+ String path = node.valueOf("@path");
+ String type = node.valueOf("@type");
+ String url = node.valueOf("@url");
+ BaseStorageResource storageResource = null == holder ? new BaseStorageResource() : holder;
+ storageResource.setDirectory("directory".equals(type));
+ storageResource.setPath(path);
+ storageResource.setUrl(url);
+
+ if (storageResource.isDirectory()) {
+ if (node.selectSingleNode("contents") != null) {
+ storageResource.setDirectoryContents(new ListParser(new StorageResourceParser(),
+ "contents/resource").parseXmlNode(node));
+ }
+ } else {
+ String name = node.valueOf("@name");
+ storageResource.setName(name);
+
+ Node meta = node.selectSingleNode("resource-meta");
+ HashMap metamap = new HashMap();
+ if (null != meta) {
+ Element metaEl = (Element) meta;
+ for (Object o : metaEl.elements()) {
+ Element sub = (Element) o;
+ metamap.put(sub.getName(), sub.getText().trim());
+ }
+ }
+ storageResource.setMetadata(metamap);
+ }
+ return storageResource;
+ }
+}
diff --git a/src/test/java/org/rundeck/api/RundeckClientTest.java b/src/test/java/org/rundeck/api/RundeckClientTest.java
index 654334d..f989e69 100644
--- a/src/test/java/org/rundeck/api/RundeckClientTest.java
+++ b/src/test/java/org/rundeck/api/RundeckClientTest.java
@@ -1280,6 +1280,215 @@ public class RundeckClientTest {
Assert.assertEquals(404, e.getStatusCode());
}
}
+ /**
+ * Store ssh key
+ */
+ @Test
+ @Betamax(tape = "ssh_key_store_private", mode = TapeMode.READ_ONLY)
+ public void storeSshKey_private() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_7, 11);
+ File temp = File.createTempFile("test-key", ".tmp");
+ temp.deleteOnExit();
+ FileOutputStream out = new FileOutputStream(temp);
+ try{
+ out.write("test1".getBytes());
+ }finally {
+ out.close();
+ }
+ SSHKeyResource storageResource = client.storeSshKey("ssh-key/test/example/file1.pem", temp, true);
+ Assert.assertNotNull(storageResource);
+ Assert.assertFalse(storageResource.isDirectory());
+ Assert.assertTrue(storageResource.isPrivateKey());
+ Assert.assertEquals("file1.pem", storageResource.getName());
+ Assert.assertEquals("ssh-key/test/example/file1.pem", storageResource.getPath());
+ Assert.assertEquals("http://dignan.local:4440/api/11/storage/ssh-key/test/example/file1.pem",
+ storageResource.getUrl());
+ Assert.assertEquals(0, storageResource.getDirectoryContents().size());
+ Map metadata = storageResource.getMetadata();
+ Assert.assertNotNull(metadata);
+ Assert.assertEquals("application/octet-stream", metadata.get("Rundeck-content-type"));
+ Assert.assertEquals("private", metadata.get("Rundeck-ssh-key-type"));
+ }
+ /**
+ * Store ssh key
+ */
+ @Test
+ @Betamax(tape = "ssh_key_store_public", mode = TapeMode.READ_ONLY)
+ public void storeSshKey_public() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_7, 11);
+ File temp = File.createTempFile("test-key", ".tmp");
+ temp.deleteOnExit();
+ FileOutputStream out = new FileOutputStream(temp);
+ try{
+ out.write("test1".getBytes());
+ }finally {
+ out.close();
+ }
+ SSHKeyResource storageResource = client.storeSshKey("ssh-key/test/example/file2.pub", temp, false);
+ Assert.assertNotNull(storageResource);
+ Assert.assertFalse(storageResource.isDirectory());
+ Assert.assertFalse(storageResource.isPrivateKey());
+ Assert.assertEquals("file2.pub", storageResource.getName());
+ Assert.assertEquals("ssh-key/test/example/file2.pub", storageResource.getPath());
+ Assert.assertEquals("http://dignan.local:4440/api/11/storage/ssh-key/test/example/file2.pub",
+ storageResource.getUrl());
+ Assert.assertEquals(0, storageResource.getDirectoryContents().size());
+ Map metadata = storageResource.getMetadata();
+ Assert.assertNotNull(metadata);
+ Assert.assertEquals("application/pgp-keys", metadata.get("Rundeck-content-type"));
+ Assert.assertEquals("public", metadata.get("Rundeck-ssh-key-type"));
+ }
+ /**
+ * get ssh key
+ */
+ @Test
+ @Betamax(tape = "ssh_key_get_public", mode = TapeMode.READ_ONLY)
+ public void getSshKey_public() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_7, 11);
+ SSHKeyResource storageResource = client.getSshKey("ssh-key/test/example/file2.pub");
+ Assert.assertNotNull(storageResource);
+ Assert.assertFalse(storageResource.isDirectory());
+ Assert.assertFalse(storageResource.isPrivateKey());
+ Assert.assertEquals("file2.pub", storageResource.getName());
+ Assert.assertEquals("ssh-key/test/example/file2.pub", storageResource.getPath());
+ Assert.assertEquals("http://dignan.local:4440/api/11/storage/ssh-key/test/example/file2.pub",
+ storageResource.getUrl());
+ Assert.assertEquals(0, storageResource.getDirectoryContents().size());
+ Map metadata = storageResource.getMetadata();
+ Assert.assertNotNull(metadata);
+ Assert.assertEquals("application/pgp-keys", metadata.get("Rundeck-content-type"));
+ Assert.assertEquals("public", metadata.get("Rundeck-ssh-key-type"));
+ }
+ /**
+ * get ssh key
+ */
+ @Test
+ @Betamax(tape = "ssh_key_get_private", mode = TapeMode.READ_ONLY)
+ public void getSshKey_private() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_7, 11);
+ SSHKeyResource storageResource = client.getSshKey("ssh-key/test/example/file1.pem");
+ Assert.assertNotNull(storageResource);
+ Assert.assertFalse(storageResource.isDirectory());
+ Assert.assertTrue(storageResource.isPrivateKey());
+ Assert.assertEquals("file1.pem", storageResource.getName());
+ Assert.assertEquals("ssh-key/test/example/file1.pem", storageResource.getPath());
+ Assert.assertEquals("http://dignan.local:4440/api/11/storage/ssh-key/test/example/file1.pem",
+ storageResource.getUrl());
+ Assert.assertEquals(0, storageResource.getDirectoryContents().size());
+ Map metadata = storageResource.getMetadata();
+ Assert.assertNotNull(metadata);
+ Assert.assertEquals("application/octet-stream", metadata.get("Rundeck-content-type"));
+ Assert.assertEquals("private", metadata.get("Rundeck-ssh-key-type"));
+ }
+ /**
+ * get ssh key data
+ */
+ @Test
+ @Betamax(tape = "ssh_key_get_data_private", mode = TapeMode.READ_ONLY)
+ public void getSshKeyData_private() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_7, 11);
+ File temp = File.createTempFile("test-key", ".tmp");
+ temp.deleteOnExit();
+ try {
+ int data = client.getPublicSshKeyContent("ssh-key/test/example/file1.pem", temp);
+ Assert.fail("expected failure");
+ } catch (RundeckApiException e) {
+ Assert.assertEquals("Requested SSH Key path was not a Public key: ssh-key/test/example/file1.pem",
+ e.getMessage());
+ }
+ }
+ /**
+ * get ssh key data
+ */
+ @Test
+ @Betamax(tape = "ssh_key_get_data_public", mode = TapeMode.READ_ONLY)
+ public void getSshKeyData_public() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_7, 11);
+ File temp = File.createTempFile("test-key", ".tmp");
+ temp.deleteOnExit();
+ int length = client.getPublicSshKeyContent("ssh-key/test/example/file2.pub", temp);
+ Assert.assertEquals(5, length);
+ }
+ /**
+ * list directory
+ */
+ @Test
+ @Betamax(tape = "ssh_key_list_directory", mode = TapeMode.READ_ONLY)
+ public void listSshKeyDirectory() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_7, 11);
+ List list = client.listSshKeyDirectory("ssh-key/test/example");
+ Assert.assertEquals(2, list.size());
+ SSHKeyResource storageResource1 = list.get(0);
+ SSHKeyResource storageResource2 = list.get(1);
+
+ Assert.assertFalse(storageResource2.isDirectory());
+ Assert.assertTrue(storageResource2.isPrivateKey());
+ Assert.assertEquals("file1.pem", storageResource2.getName());
+ Assert.assertEquals("ssh-key/test/example/file1.pem", storageResource2.getPath());
+ Assert.assertEquals("http://dignan.local:4440/api/11/storage/ssh-key/test/example/file1.pem", storageResource2.getUrl());
+ Assert.assertNotNull(storageResource2.getMetadata());
+
+ Assert.assertEquals("application/octet-stream", storageResource2.getMetadata().get("Rundeck-content-type"));
+ Assert.assertEquals("private", storageResource2.getMetadata().get("Rundeck-ssh-key-type"));
+
+ Assert.assertFalse(storageResource1.isDirectory());
+ Assert.assertFalse(storageResource1.isPrivateKey());
+ Assert.assertEquals("file2.pub", storageResource1.getName());
+ Assert.assertEquals("ssh-key/test/example/file2.pub", storageResource1.getPath());
+ Assert.assertEquals("http://dignan.local:4440/api/11/storage/ssh-key/test/example/file2.pub",
+ storageResource1.getUrl());
+ Assert.assertNotNull(storageResource1.getMetadata());
+ Assert.assertEquals("application/pgp-keys", storageResource1.getMetadata().get("Rundeck-content-type"));
+ Assert.assertEquals("public", storageResource1.getMetadata().get("Rundeck-ssh-key-type"));
+ }
+ /**
+ * list root
+ */
+ @Test
+ @Betamax(tape = "ssh_key_list_root", mode = TapeMode.READ_ONLY)
+ public void listSshKeyDirectoryRoot() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_7, 11);
+ List list = client.listSshKeyDirectoryRoot();
+ Assert.assertEquals(2, list.size());
+ SSHKeyResource storageResource0 = list.get(0);
+ SSHKeyResource storageResource1 = list.get(1);
+
+ Assert.assertFalse(storageResource0.isDirectory());
+ Assert.assertTrue(storageResource0.isPrivateKey());
+ Assert.assertEquals("test1.pem", storageResource0.getName());
+ Assert.assertEquals("ssh-key/test1.pem", storageResource0.getPath());
+ Assert.assertEquals("http://dignan.local:4440/api/11/storage/ssh-key/test1.pem", storageResource0.getUrl());
+ Assert.assertNotNull(storageResource0.getMetadata());
+
+ Assert.assertEquals("application/octet-stream", storageResource0.getMetadata().get("Rundeck-content-type"));
+ Assert.assertEquals("private", storageResource0.getMetadata().get("Rundeck-ssh-key-type"));
+
+ Assert.assertTrue(storageResource1.toString(), storageResource1.isDirectory());
+ Assert.assertEquals(null, storageResource1.getName());
+ Assert.assertEquals("ssh-key/test", storageResource1.getPath());
+ Assert.assertEquals("http://dignan.local:4440/api/11/storage/ssh-key/test",
+ storageResource1.getUrl());
+ Assert.assertNull(storageResource1.getMetadata());
+
+
+ }
+
+ /**
+ * delete ssh key
+ */
+ @Test
+ @Betamax(tape = "ssh_key_delete", mode = TapeMode.READ_ONLY)
+ public void deleteSshKey() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_7, 11);
+ client.deleteSshKey("ssh-key/test/example/file2.pub");
+
+ try {
+ client.getSshKey("ssh-key/test/example/file2.pub");
+ Assert.fail("expected failure");
+ } catch (RundeckApiException.RundeckApiHttpStatusException e) {
+ Assert.assertEquals(404,e.getStatusCode());
+ }
+ }
@Before
public void setUp() throws Exception {
diff --git a/src/test/resources/betamax/tapes/ssh_key_delete.yaml b/src/test/resources/betamax/tapes/ssh_key_delete.yaml
new file mode 100644
index 0000000..fd46eae
--- /dev/null
+++ b/src/test/resources/betamax/tapes/ssh_key_delete.yaml
@@ -0,0 +1,36 @@
+!tape
+name: ssh_key_delete
+interactions:
+- recorded: 2014-04-04T23:16:02.256Z
+ request:
+ method: DELETE
+ uri: http://rundeck.local:4440/api/11/storage/ssh-key/test/example/file2.pub
+ headers:
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
+ response:
+ status: 204
+ headers:
+ Content-Type: text/html;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=3rsjs6vicpc619b1uy7oshp4y;Path=/
+- recorded: 2014-04-04T23:16:02.372Z
+ request:
+ method: GET
+ uri: http://rundeck.local:4440/api/11/storage/ssh-key/test/example/file2.pub
+ headers:
+ Accept: text/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
+ response:
+ status: 404
+ headers:
+ Content-Type: application/xml;charset=utf-8
+ Server: Jetty(7.6.0.v20120127)
+ body: !!binary |-
+ PGVycm9yPnJlc291cmNlIG5vdCBmb3VuZDogL3NzaC1rZXkvdGVzdC9leGFtcGxlL2ZpbGUyLnB1YjwvZXJyb3I+
diff --git a/src/test/resources/betamax/tapes/ssh_key_get_data_private.yaml b/src/test/resources/betamax/tapes/ssh_key_get_data_private.yaml
new file mode 100644
index 0000000..e5e742b
--- /dev/null
+++ b/src/test/resources/betamax/tapes/ssh_key_get_data_private.yaml
@@ -0,0 +1,22 @@
+!tape
+name: ssh_key_get_data_private
+interactions:
+- recorded: 2014-04-04T19:50:59.155Z
+ request:
+ method: GET
+ uri: http://rundeck.local:4440/api/11/storage/ssh-key/test/example/file1.pem
+ headers:
+ Accept: application/pgp-keys
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
+ response:
+ status: 200
+ headers:
+ Content-Type: application/json;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=1gzu37lkjr0fitxhf5fgkgsfu;Path=/
+ body: !!binary |-
+ eyJwYXRoIjoic3NoLWtleS90ZXN0L2V4YW1wbGUvZmlsZTEucGVtIiwidHlwZSI6ImZpbGUiLCJuYW1lIjoiZmlsZTEucGVtIiwidXJsIjoiaHR0cDovL2RpZ25hbi5sb2NhbDo0NDQwL2FwaS8xMS9zdG9yYWdlL3NzaC1rZXkvdGVzdC9leGFtcGxlL2ZpbGUxLnBlbSIsIm1ldGEiOnsiUnVuZGVjay1jb250ZW50LXR5cGUiOiJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0iLCJSdW5kZWNrLWNvbnRlbnQtc2l6ZSI6IjUiLCJSdW5kZWNrLWNvbnRlbnQtbWFzayI6ImNvbnRlbnQiLCJSdW5kZWNrLXNzaC1rZXktdHlwZSI6InByaXZhdGUifX0=
diff --git a/src/test/resources/betamax/tapes/ssh_key_get_data_public.yaml b/src/test/resources/betamax/tapes/ssh_key_get_data_public.yaml
new file mode 100644
index 0000000..1874e71
--- /dev/null
+++ b/src/test/resources/betamax/tapes/ssh_key_get_data_public.yaml
@@ -0,0 +1,22 @@
+!tape
+name: ssh_key_get_data_public
+interactions:
+- recorded: 2014-04-04T20:20:44.331Z
+ request:
+ method: GET
+ uri: http://rundeck.local:4440/api/11/storage/ssh-key/test/example/file2.pub
+ headers:
+ Accept: application/pgp-keys
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
+ response:
+ status: 200
+ headers:
+ Content-Type: application/pgp-keys
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=1mrub15qsorpf10cisx24h8h03;Path=/
+ body: !!binary |-
+ dGVzdDE=
diff --git a/src/test/resources/betamax/tapes/ssh_key_get_private.yaml b/src/test/resources/betamax/tapes/ssh_key_get_private.yaml
new file mode 100644
index 0000000..fa0ff2c
--- /dev/null
+++ b/src/test/resources/betamax/tapes/ssh_key_get_private.yaml
@@ -0,0 +1,22 @@
+!tape
+name: ssh_key_get_private
+interactions:
+- recorded: 2014-04-04T19:47:29.880Z
+ request:
+ method: GET
+ uri: http://rundeck.local:4440/api/11/storage/ssh-key/test/example/file1.pem
+ headers:
+ Accept: text/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
+ response:
+ status: 200
+ headers:
+ Content-Type: application/xml;charset=utf-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=nc5p0he3nw19e4gegidc4bs7;Path=/
+ body: !!binary |-
+ PHJlc291cmNlIHBhdGg9J3NzaC1rZXkvdGVzdC9leGFtcGxlL2ZpbGUxLnBlbScgdHlwZT0nZmlsZScgdXJsPSdodHRwOi8vZGlnbmFuLmxvY2FsOjQ0NDAvYXBpLzExL3N0b3JhZ2Uvc3NoLWtleS90ZXN0L2V4YW1wbGUvZmlsZTEucGVtJyBuYW1lPSdmaWxlMS5wZW0nPjxyZXNvdXJjZS1tZXRhPjxSdW5kZWNrLWNvbnRlbnQtdHlwZT5hcHBsaWNhdGlvbi9vY3RldC1zdHJlYW08L1J1bmRlY2stY29udGVudC10eXBlPjxSdW5kZWNrLWNvbnRlbnQtc2l6ZT41PC9SdW5kZWNrLWNvbnRlbnQtc2l6ZT48UnVuZGVjay1jb250ZW50LW1hc2s+Y29udGVudDwvUnVuZGVjay1jb250ZW50LW1hc2s+PFJ1bmRlY2stc3NoLWtleS10eXBlPnByaXZhdGU8L1J1bmRlY2stc3NoLWtleS10eXBlPjwvcmVzb3VyY2UtbWV0YT48L3Jlc291cmNlPg==
diff --git a/src/test/resources/betamax/tapes/ssh_key_get_public.yaml b/src/test/resources/betamax/tapes/ssh_key_get_public.yaml
new file mode 100644
index 0000000..8bede8d
--- /dev/null
+++ b/src/test/resources/betamax/tapes/ssh_key_get_public.yaml
@@ -0,0 +1,22 @@
+!tape
+name: ssh_key_get_public
+interactions:
+- recorded: 2014-04-04T19:47:29.626Z
+ request:
+ method: GET
+ uri: http://rundeck.local:4440/api/11/storage/ssh-key/test/example/file2.pub
+ headers:
+ Accept: text/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
+ response:
+ status: 200
+ headers:
+ Content-Type: application/xml;charset=utf-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=r6p6fl87ftrb1mkwwi0pcak5i;Path=/
+ body: !!binary |-
+ PHJlc291cmNlIHBhdGg9J3NzaC1rZXkvdGVzdC9leGFtcGxlL2ZpbGUyLnB1YicgdHlwZT0nZmlsZScgdXJsPSdodHRwOi8vZGlnbmFuLmxvY2FsOjQ0NDAvYXBpLzExL3N0b3JhZ2Uvc3NoLWtleS90ZXN0L2V4YW1wbGUvZmlsZTIucHViJyBuYW1lPSdmaWxlMi5wdWInPjxyZXNvdXJjZS1tZXRhPjxSdW5kZWNrLWNvbnRlbnQtdHlwZT5hcHBsaWNhdGlvbi9wZ3Ata2V5czwvUnVuZGVjay1jb250ZW50LXR5cGU+PFJ1bmRlY2stY29udGVudC1zaXplPjU8L1J1bmRlY2stY29udGVudC1zaXplPjxSdW5kZWNrLXNzaC1rZXktdHlwZT5wdWJsaWM8L1J1bmRlY2stc3NoLWtleS10eXBlPjwvcmVzb3VyY2UtbWV0YT48L3Jlc291cmNlPg==
diff --git a/src/test/resources/betamax/tapes/ssh_key_list_directory.yaml b/src/test/resources/betamax/tapes/ssh_key_list_directory.yaml
new file mode 100644
index 0000000..e49f941
--- /dev/null
+++ b/src/test/resources/betamax/tapes/ssh_key_list_directory.yaml
@@ -0,0 +1,21 @@
+!tape
+name: ssh_key_list_directory
+interactions:
+- recorded: 2014-04-04T20:33:07.968Z
+ request:
+ method: GET
+ uri: http://rundeck.local:4440/api/11/storage/ssh-key/test/example
+ headers:
+ Accept: text/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
+ response:
+ status: 200
+ headers:
+ Content-Type: text/html;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=1stwtoatsosy91ca0gcrzde698;Path=/
+ body: application/pgp-keys 5 public application/octet-stream 5 content private
diff --git a/src/test/resources/betamax/tapes/ssh_key_list_root.yaml b/src/test/resources/betamax/tapes/ssh_key_list_root.yaml
new file mode 100644
index 0000000..dcefe5e
--- /dev/null
+++ b/src/test/resources/betamax/tapes/ssh_key_list_root.yaml
@@ -0,0 +1,21 @@
+!tape
+name: ssh_key_list_root
+interactions:
+- recorded: 2014-04-04T20:41:16.501Z
+ request:
+ method: GET
+ uri: http://rundeck.local:4440/api/11/storage/ssh-key/
+ headers:
+ Accept: text/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
+ response:
+ status: 200
+ headers:
+ Content-Type: text/html;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=5sj36vytg4y1182mziim4868b;Path=/
+ body: application/octet-stream 1679 content private
diff --git a/src/test/resources/betamax/tapes/ssh_key_store_private.yaml b/src/test/resources/betamax/tapes/ssh_key_store_private.yaml
new file mode 100644
index 0000000..6ef2def
--- /dev/null
+++ b/src/test/resources/betamax/tapes/ssh_key_store_private.yaml
@@ -0,0 +1,25 @@
+!tape
+name: ssh_key_store_private
+interactions:
+- recorded: 2014-04-04T19:30:35.367Z
+ request:
+ method: POST
+ uri: http://rundeck.local:4440/api/11/storage/ssh-key/test/example/file1.pem
+ headers:
+ Accept: text/xml
+ Content-Length: '5'
+ Content-Type: application/octet-stream
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
+ body: ''
+ response:
+ status: 201
+ headers:
+ Content-Type: application/xml;charset=utf-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=ktmwc4h53xfud6v2ch67x5p9;Path=/
+ body: !!binary |-
+ PHJlc291cmNlIHBhdGg9J3NzaC1rZXkvdGVzdC9leGFtcGxlL2ZpbGUxLnBlbScgdHlwZT0nZmlsZScgdXJsPSdodHRwOi8vZGlnbmFuLmxvY2FsOjQ0NDAvYXBpLzExL3N0b3JhZ2Uvc3NoLWtleS90ZXN0L2V4YW1wbGUvZmlsZTEucGVtJyBuYW1lPSdmaWxlMS5wZW0nPjxyZXNvdXJjZS1tZXRhPjxSdW5kZWNrLWNvbnRlbnQtdHlwZT5hcHBsaWNhdGlvbi9vY3RldC1zdHJlYW08L1J1bmRlY2stY29udGVudC10eXBlPjxSdW5kZWNrLWNvbnRlbnQtc2l6ZT41PC9SdW5kZWNrLWNvbnRlbnQtc2l6ZT48UnVuZGVjay1jb250ZW50LW1hc2s+Y29udGVudDwvUnVuZGVjay1jb250ZW50LW1hc2s+PFJ1bmRlY2stc3NoLWtleS10eXBlPnByaXZhdGU8L1J1bmRlY2stc3NoLWtleS10eXBlPjwvcmVzb3VyY2UtbWV0YT48L3Jlc291cmNlPg==
diff --git a/src/test/resources/betamax/tapes/ssh_key_store_public.yaml b/src/test/resources/betamax/tapes/ssh_key_store_public.yaml
new file mode 100644
index 0000000..8a1b18a
--- /dev/null
+++ b/src/test/resources/betamax/tapes/ssh_key_store_public.yaml
@@ -0,0 +1,25 @@
+!tape
+name: ssh_key_store_public
+interactions:
+- recorded: 2014-04-04T19:34:02.683Z
+ request:
+ method: POST
+ uri: http://rundeck.local:4440/api/11/storage/ssh-key/test/example/file2.pub
+ headers:
+ Accept: text/xml
+ Content-Length: '5'
+ Content-Type: application/pgp-keys
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
+ body: ''
+ response:
+ status: 201
+ headers:
+ Content-Type: application/xml;charset=utf-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=2l3g8m0tvwef19jn2bu23bzk6;Path=/
+ body: !!binary |-
+ PHJlc291cmNlIHBhdGg9J3NzaC1rZXkvdGVzdC9leGFtcGxlL2ZpbGUyLnB1YicgdHlwZT0nZmlsZScgdXJsPSdodHRwOi8vZGlnbmFuLmxvY2FsOjQ0NDAvYXBpLzExL3N0b3JhZ2Uvc3NoLWtleS90ZXN0L2V4YW1wbGUvZmlsZTIucHViJyBuYW1lPSdmaWxlMi5wdWInPjxyZXNvdXJjZS1tZXRhPjxSdW5kZWNrLWNvbnRlbnQtdHlwZT5hcHBsaWNhdGlvbi9wZ3Ata2V5czwvUnVuZGVjay1jb250ZW50LXR5cGU+PFJ1bmRlY2stY29udGVudC1zaXplPjU8L1J1bmRlY2stY29udGVudC1zaXplPjxSdW5kZWNrLXNzaC1rZXktdHlwZT5wdWJsaWM8L1J1bmRlY2stc3NoLWtleS10eXBlPjwvcmVzb3VyY2UtbWV0YT48L3Jlc291cmNlPg==
From 89452e731a3faea711b70442ae6311ad88e7bee2 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Fri, 4 Apr 2014 16:39:52 -0700
Subject: [PATCH 53/89] Update ssh key api todo
---
src/site/confluence/status.confluence | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/site/confluence/status.confluence b/src/site/confluence/status.confluence
index 0dfbb3e..3042fa8 100644
--- a/src/site/confluence/status.confluence
+++ b/src/site/confluence/status.confluence
@@ -106,10 +106,10 @@ h2. RunDeck API version 11
* Delete project - OK
* Export project archive - OK
* Import project archive - OK
-* SSH Key upload - *TODO*
-* SSH Key delete - *TODO*
-* SSH Key list - *TODO*
-* SSH Key get - *TODO*
+* SSH Key upload - OK
+* SSH Key delete - OK
+* SSH Key list - OK
+* SSH Key get - OK
* API Token create - OK
* API Token list - OK
* API Token delete - OK
From a59246bdf3e1064abb1086205016fa0481651137 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Wed, 23 Apr 2014 16:18:41 -0700
Subject: [PATCH 54/89] Api sync for key storage
* change ssh-key/ to keys/ in api paths
---
.../java/org/rundeck/api/RundeckClient.java | 92 +++++++-------
...HKeyResource.java => BaseKeyResource.java} | 23 ++--
.../{SSHKeyResource.java => KeyResource.java} | 6 +-
.../api/parser/SSHKeyResourceParser.java | 11 +-
.../org/rundeck/api/RundeckClientTest.java | 112 +++++++++---------
.../{ssh_key_delete.yaml => key_delete.yaml} | 4 +-
...private.yaml => key_get_data_private.yaml} | 5 +-
...a_public.yaml => key_get_data_public.yaml} | 2 +-
.../betamax/tapes/key_get_private.yaml | 23 ++++
...ey_get_public.yaml => key_get_public.yaml} | 5 +-
.../betamax/tapes/key_list_directory.yaml | 21 ++++
.../betamax/tapes/key_list_root.yaml | 21 ++++
...re_private.yaml => key_store_private.yaml} | 5 +-
...tore_public.yaml => key_store_public.yaml} | 5 +-
.../betamax/tapes/ssh_key_get_private.yaml | 22 ----
.../betamax/tapes/ssh_key_list_directory.yaml | 21 ----
.../betamax/tapes/ssh_key_list_root.yaml | 21 ----
17 files changed, 200 insertions(+), 199 deletions(-)
rename src/main/java/org/rundeck/api/domain/{BaseSSHKeyResource.java => BaseKeyResource.java} (65%)
rename src/main/java/org/rundeck/api/domain/{SSHKeyResource.java => KeyResource.java} (68%)
rename src/test/resources/betamax/tapes/{ssh_key_delete.yaml => key_delete.yaml} (86%)
rename src/test/resources/betamax/tapes/{ssh_key_get_data_private.yaml => key_get_data_private.yaml} (54%)
rename src/test/resources/betamax/tapes/{ssh_key_get_data_public.yaml => key_get_data_public.yaml} (88%)
create mode 100644 src/test/resources/betamax/tapes/key_get_private.yaml
rename src/test/resources/betamax/tapes/{ssh_key_get_public.yaml => key_get_public.yaml} (50%)
create mode 100644 src/test/resources/betamax/tapes/key_list_directory.yaml
create mode 100644 src/test/resources/betamax/tapes/key_list_root.yaml
rename src/test/resources/betamax/tapes/{ssh_key_store_private.yaml => key_store_private.yaml} (50%)
rename src/test/resources/betamax/tapes/{ssh_key_store_public.yaml => key_store_public.yaml} (53%)
delete mode 100644 src/test/resources/betamax/tapes/ssh_key_get_private.yaml
delete mode 100644 src/test/resources/betamax/tapes/ssh_key_list_directory.yaml
delete mode 100644 src/test/resources/betamax/tapes/ssh_key_list_root.yaml
diff --git a/src/main/java/org/rundeck/api/RundeckClient.java b/src/main/java/org/rundeck/api/RundeckClient.java
index b0baa4c..8462dba 100644
--- a/src/main/java/org/rundeck/api/RundeckClient.java
+++ b/src/main/java/org/rundeck/api/RundeckClient.java
@@ -82,7 +82,7 @@ public class RundeckClient implements Serializable {
private static final long serialVersionUID = 1L;
public static final String JOBS_IMPORT = "/jobs/import";
public static final String STORAGE_ROOT_PATH = "/storage/";
- public static final String SSH_KEY_PATH = "ssh-key/";
+ public static final String STORAGE_KEYS_PATH = "keys/";
/**
* Supported version numbers
@@ -2375,18 +2375,18 @@ public class RundeckClient implements Serializable {
}
/**
- * Store an SSH key file
- * @param path ssh key storage path, must start with "ssh-key/"
+ * Store an key file
+ * @param path ssh key storage path, must start with "keys/"
* @param keyfile key file
* @param privateKey true to store private key, false to store public key
- * @return the SSH key resource
+ * @return the key resource
* @throws RundeckApiException
*/
- public SSHKeyResource storeSshKey(final String path, final File keyfile, boolean privateKey) throws RundeckApiException{
- AssertUtil.notNull(path, "path is mandatory to store an SSH key.");
- AssertUtil.notNull(keyfile, "keyfile is mandatory to store an SSH key.");
- if (!path.startsWith(SSH_KEY_PATH)) {
- throw new IllegalArgumentException("SSH key storage path must start with: " + SSH_KEY_PATH);
+ public KeyResource storeKey(final String path, final File keyfile, boolean privateKey) throws RundeckApiException{
+ AssertUtil.notNull(path, "path is mandatory to store an key.");
+ AssertUtil.notNull(keyfile, "keyfile is mandatory to store an key.");
+ if (!path.startsWith(STORAGE_KEYS_PATH)) {
+ throw new IllegalArgumentException("key storage path must start with: " + STORAGE_KEYS_PATH);
}
return new ApiCall(this).post(
new ApiPathBuilder(STORAGE_ROOT_PATH, path).content(
@@ -2398,42 +2398,42 @@ public class RundeckClient implements Serializable {
}
/**
- * Get metadata for an SSH key file
+ * Get metadata for an key file
*
- * @param path ssh key storage path, must start with "ssh-key/"
+ * @param path ssh key storage path, must start with "keys/"
*
* @return the ssh key resource
*
* @throws RundeckApiException if there is an error, or if the path is a directory not a file
*/
- public SSHKeyResource getSshKey(final String path) throws RundeckApiException {
- AssertUtil.notNull(path, "path is mandatory to get an SSH key.");
- if (!path.startsWith(SSH_KEY_PATH)) {
- throw new IllegalArgumentException("SSH key storage path must start with: " + SSH_KEY_PATH);
+ public KeyResource getKey(final String path) throws RundeckApiException {
+ AssertUtil.notNull(path, "path is mandatory to get an key.");
+ if (!path.startsWith(STORAGE_KEYS_PATH)) {
+ throw new IllegalArgumentException("key storage path must start with: " + STORAGE_KEYS_PATH);
}
- SSHKeyResource storageResource = new ApiCall(this).get(
+ KeyResource storageResource = new ApiCall(this).get(
new ApiPathBuilder(STORAGE_ROOT_PATH, path),
new SSHKeyResourceParser("/resource")
);
if (storageResource.isDirectory()) {
- throw new RundeckApiException("SSH Key Path is a directory: " + path);
+ throw new RundeckApiException("Key Path is a directory: " + path);
}
return storageResource;
}
/**
- * Get content for a public SSH key file
- * @param path ssh key storage path, must start with "ssh-key/"
+ * Get content for a public key file
+ * @param path ssh key storage path, must start with "keys/"
* @param out outputstream to write data to
*
* @return length of written data
* @throws RundeckApiException
*/
- public int getPublicSshKeyContent(final String path, final OutputStream out) throws
+ public int getPublicKeyContent(final String path, final OutputStream out) throws
RundeckApiException, IOException {
- AssertUtil.notNull(path, "path is mandatory to get an SSH key.");
- if (!path.startsWith(SSH_KEY_PATH)) {
- throw new IllegalArgumentException("SSH key storage path must start with: " + SSH_KEY_PATH);
+ AssertUtil.notNull(path, "path is mandatory to get an key.");
+ if (!path.startsWith(STORAGE_KEYS_PATH)) {
+ throw new IllegalArgumentException("key storage path must start with: " + STORAGE_KEYS_PATH);
}
try {
return new ApiCall(this).get(
@@ -2443,66 +2443,66 @@ public class RundeckClient implements Serializable {
out
);
} catch (RundeckApiException.RundeckApiHttpContentTypeException e) {
- throw new RundeckApiException("Requested SSH Key path was not a Public key: " + path, e);
+ throw new RundeckApiException("Requested Key path was not a Public key: " + path, e);
}
}
/**
- * Get content for a public SSH key file
- * @param path ssh key storage path, must start with "ssh-key/"
+ * Get content for a public key file
+ * @param path ssh key storage path, must start with "keys/"
* @param out file to write data to
* @return length of written data
* @throws RundeckApiException
*/
- public int getPublicSshKeyContent(final String path, final File out) throws
+ public int getPublicKeyContent(final String path, final File out) throws
RundeckApiException, IOException {
final FileOutputStream fileOutputStream = new FileOutputStream(out);
try {
- return getPublicSshKeyContent(path, fileOutputStream);
+ return getPublicKeyContent(path, fileOutputStream);
}finally {
fileOutputStream.close();
}
}
/**
- * List contents of root SSH key directory
+ * List contents of root key directory
*
- * @return list of SSH key resources
+ * @return list of key resources
* @throws RundeckApiException
*/
- public List listSshKeyDirectoryRoot() throws RundeckApiException {
- return listSshKeyDirectory(SSH_KEY_PATH);
+ public List listKeyDirectoryRoot() throws RundeckApiException {
+ return listKeyDirectory(STORAGE_KEYS_PATH);
}
/**
- * List contents of SSH key directory
+ * List contents of key directory
*
- * @param path ssh key storage path, must start with "ssh-key/"
+ * @param path ssh key storage path, must start with "keys/"
*
* @throws RundeckApiException if there is an error, or if the path is a file not a directory
*/
- public List listSshKeyDirectory(final String path) throws RundeckApiException {
- AssertUtil.notNull(path, "path is mandatory to get an SSH key.");
- if (!path.startsWith(SSH_KEY_PATH)) {
- throw new IllegalArgumentException("SSH key storage path must start with: " + SSH_KEY_PATH);
+ public List listKeyDirectory(final String path) throws RundeckApiException {
+ AssertUtil.notNull(path, "path is mandatory to get an key.");
+ if (!path.startsWith(STORAGE_KEYS_PATH)) {
+ throw new IllegalArgumentException("key storage path must start with: " + STORAGE_KEYS_PATH);
}
- SSHKeyResource storageResource = new ApiCall(this).get(
+ KeyResource storageResource = new ApiCall(this).get(
new ApiPathBuilder(STORAGE_ROOT_PATH, path),
new SSHKeyResourceParser("/resource")
);
if(!storageResource.isDirectory()) {
- throw new RundeckApiException("SSH key path is not a directory path: " + path);
+ throw new RundeckApiException("key path is not a directory path: " + path);
}
return storageResource.getDirectoryContents();
}
/**
- * Delete an SSH key file
- * @param path a path to a SSH key file, must start with "ssh-key/"
+ * Delete an key file
+ * @param path a path to a key file, must start with "keys/"
*/
- public void deleteSshKey(final String path){
- AssertUtil.notNull(path, "path is mandatory to delete an SSH key.");
- if (!path.startsWith(SSH_KEY_PATH)) {
- throw new IllegalArgumentException("SSH key storage path must start with: " + SSH_KEY_PATH);
+ public void deleteKey(final String path){
+ AssertUtil.notNull(path, "path is mandatory to delete an key.");
+ if (!path.startsWith(STORAGE_KEYS_PATH)) {
+ throw new IllegalArgumentException("key storage path must start with: " + STORAGE_KEYS_PATH);
}
new ApiCall(this).delete(new ApiPathBuilder(STORAGE_ROOT_PATH, path));
}
diff --git a/src/main/java/org/rundeck/api/domain/BaseSSHKeyResource.java b/src/main/java/org/rundeck/api/domain/BaseKeyResource.java
similarity index 65%
rename from src/main/java/org/rundeck/api/domain/BaseSSHKeyResource.java
rename to src/main/java/org/rundeck/api/domain/BaseKeyResource.java
index b47d878..c1ed3b7 100644
--- a/src/main/java/org/rundeck/api/domain/BaseSSHKeyResource.java
+++ b/src/main/java/org/rundeck/api/domain/BaseKeyResource.java
@@ -1,21 +1,18 @@
package org.rundeck.api.domain;
-import org.rundeck.api.RundeckClient;
-import org.rundeck.api.parser.StorageResourceParser;
-
import java.util.ArrayList;
import java.util.List;
/**
- * BaseSSHKeyResource is ...
+ * BaseKeyResource is ...
*
* @author Greg Schueler
* @since 2014-04-04
*/
-public class BaseSSHKeyResource extends BaseStorageResource implements SSHKeyResource {
+public class BaseKeyResource extends BaseStorageResource implements KeyResource {
private boolean privateKey;
- public BaseSSHKeyResource() {
+ public BaseKeyResource() {
}
@@ -27,22 +24,22 @@ public class BaseSSHKeyResource extends BaseStorageResource implements SSHKeyRes
this.privateKey = privateKey;
}
- ArrayList sshKeyResources = new ArrayList();
+ ArrayList keyResources = new ArrayList();
@Override
public void setDirectoryContents(List extends StorageResource> directoryContents) {
for (StorageResource directoryContent : directoryContents) {
- sshKeyResources.add(from(directoryContent));
+ keyResources.add(from(directoryContent));
}
}
@Override
- public List getDirectoryContents() {
- return sshKeyResources;
+ public List getDirectoryContents() {
+ return keyResources;
}
- public static BaseSSHKeyResource from(final StorageResource source) {
- final BaseSSHKeyResource baseSshKeyResource = new BaseSSHKeyResource();
+ public static BaseKeyResource from(final StorageResource source) {
+ final BaseKeyResource baseSshKeyResource = new BaseKeyResource();
baseSshKeyResource.setDirectory(source.isDirectory());
baseSshKeyResource.setPath(source.getPath());
baseSshKeyResource.setName(source.getName());
@@ -51,7 +48,7 @@ public class BaseSSHKeyResource extends BaseStorageResource implements SSHKeyRes
if (!baseSshKeyResource.isDirectory()) {
baseSshKeyResource.setPrivateKey(
null != baseSshKeyResource.getMetadata() && "private".equals(baseSshKeyResource.getMetadata().get
- ("Rundeck-ssh-key-type"))
+ ("Rundeck-key-type"))
);
} else if (null != source.getDirectoryContents()) {
baseSshKeyResource.setDirectoryContents(source.getDirectoryContents());
diff --git a/src/main/java/org/rundeck/api/domain/SSHKeyResource.java b/src/main/java/org/rundeck/api/domain/KeyResource.java
similarity index 68%
rename from src/main/java/org/rundeck/api/domain/SSHKeyResource.java
rename to src/main/java/org/rundeck/api/domain/KeyResource.java
index 33bbbd5..ff1f7e1 100644
--- a/src/main/java/org/rundeck/api/domain/SSHKeyResource.java
+++ b/src/main/java/org/rundeck/api/domain/KeyResource.java
@@ -3,12 +3,12 @@ package org.rundeck.api.domain;
import java.util.List;
/**
- * SSHKeyResource represents a directory or an SSH key file
+ * KeyResource represents a directory or an SSH key file
*
* @author Greg Schueler
* @since 2014-04-04
*/
-public interface SSHKeyResource extends StorageResource {
+public interface KeyResource extends StorageResource {
/**
* Return true if this is a file and is a private SSH key file.
* @return
@@ -19,5 +19,5 @@ public interface SSHKeyResource extends StorageResource {
* Return the list of SSH Key resources if this is a directory
* @return
*/
- public List getDirectoryContents();
+ public List getDirectoryContents();
}
diff --git a/src/main/java/org/rundeck/api/parser/SSHKeyResourceParser.java b/src/main/java/org/rundeck/api/parser/SSHKeyResourceParser.java
index 5485d31..091ab2b 100644
--- a/src/main/java/org/rundeck/api/parser/SSHKeyResourceParser.java
+++ b/src/main/java/org/rundeck/api/parser/SSHKeyResourceParser.java
@@ -1,9 +1,8 @@
package org.rundeck.api.parser;
import org.dom4j.Node;
-import org.rundeck.api.RundeckClient;
-import org.rundeck.api.domain.BaseSSHKeyResource;
-import org.rundeck.api.domain.SSHKeyResource;
+import org.rundeck.api.domain.BaseKeyResource;
+import org.rundeck.api.domain.KeyResource;
/**
* SSHKeyResourceParser is ...
@@ -11,7 +10,7 @@ import org.rundeck.api.domain.SSHKeyResource;
* @author Greg Schueler
* @since 2014-04-04
*/
-public class SSHKeyResourceParser extends BaseXpathParser implements XmlNodeParser {
+public class SSHKeyResourceParser extends BaseXpathParser implements XmlNodeParser {
public SSHKeyResourceParser() {
}
@@ -20,7 +19,7 @@ public class SSHKeyResourceParser extends BaseXpathParser implem
}
@Override
- public SSHKeyResource parse(Node node) {
- return BaseSSHKeyResource.from(new StorageResourceParser().parse(node));
+ public KeyResource parse(Node node) {
+ return BaseKeyResource.from(new StorageResourceParser().parse(node));
}
}
diff --git a/src/test/java/org/rundeck/api/RundeckClientTest.java b/src/test/java/org/rundeck/api/RundeckClientTest.java
index f989e69..fb01b80 100644
--- a/src/test/java/org/rundeck/api/RundeckClientTest.java
+++ b/src/test/java/org/rundeck/api/RundeckClientTest.java
@@ -1284,8 +1284,8 @@ public class RundeckClientTest {
* Store ssh key
*/
@Test
- @Betamax(tape = "ssh_key_store_private", mode = TapeMode.READ_ONLY)
- public void storeSshKey_private() throws Exception {
+ @Betamax(tape = "key_store_private", mode = TapeMode.READ_ONLY)
+ public void storeKey_private() throws Exception {
final RundeckClient client = createClient(TEST_TOKEN_7, 11);
File temp = File.createTempFile("test-key", ".tmp");
temp.deleteOnExit();
@@ -1295,26 +1295,26 @@ public class RundeckClientTest {
}finally {
out.close();
}
- SSHKeyResource storageResource = client.storeSshKey("ssh-key/test/example/file1.pem", temp, true);
+ KeyResource storageResource = client.storeKey("keys/test/example/file1.pem", temp, true);
Assert.assertNotNull(storageResource);
Assert.assertFalse(storageResource.isDirectory());
Assert.assertTrue(storageResource.isPrivateKey());
Assert.assertEquals("file1.pem", storageResource.getName());
- Assert.assertEquals("ssh-key/test/example/file1.pem", storageResource.getPath());
- Assert.assertEquals("http://dignan.local:4440/api/11/storage/ssh-key/test/example/file1.pem",
+ Assert.assertEquals("keys/test/example/file1.pem", storageResource.getPath());
+ Assert.assertEquals("http://dignan.local:4440/api/11/storage/keys/test/example/file1.pem",
storageResource.getUrl());
Assert.assertEquals(0, storageResource.getDirectoryContents().size());
Map metadata = storageResource.getMetadata();
Assert.assertNotNull(metadata);
Assert.assertEquals("application/octet-stream", metadata.get("Rundeck-content-type"));
- Assert.assertEquals("private", metadata.get("Rundeck-ssh-key-type"));
+ Assert.assertEquals("private", metadata.get("Rundeck-key-type"));
}
/**
* Store ssh key
*/
@Test
- @Betamax(tape = "ssh_key_store_public", mode = TapeMode.READ_ONLY)
- public void storeSshKey_public() throws Exception {
+ @Betamax(tape = "key_store_public", mode = TapeMode.READ_ONLY)
+ public void storeKey_public() throws Exception {
final RundeckClient client = createClient(TEST_TOKEN_7, 11);
File temp = File.createTempFile("test-key", ".tmp");
temp.deleteOnExit();
@@ -1324,76 +1324,76 @@ public class RundeckClientTest {
}finally {
out.close();
}
- SSHKeyResource storageResource = client.storeSshKey("ssh-key/test/example/file2.pub", temp, false);
+ KeyResource storageResource = client.storeKey("keys/test/example/file2.pub", temp, false);
Assert.assertNotNull(storageResource);
Assert.assertFalse(storageResource.isDirectory());
Assert.assertFalse(storageResource.isPrivateKey());
Assert.assertEquals("file2.pub", storageResource.getName());
- Assert.assertEquals("ssh-key/test/example/file2.pub", storageResource.getPath());
- Assert.assertEquals("http://dignan.local:4440/api/11/storage/ssh-key/test/example/file2.pub",
+ Assert.assertEquals("keys/test/example/file2.pub", storageResource.getPath());
+ Assert.assertEquals("http://dignan.local:4440/api/11/storage/keys/test/example/file2.pub",
storageResource.getUrl());
Assert.assertEquals(0, storageResource.getDirectoryContents().size());
Map metadata = storageResource.getMetadata();
Assert.assertNotNull(metadata);
Assert.assertEquals("application/pgp-keys", metadata.get("Rundeck-content-type"));
- Assert.assertEquals("public", metadata.get("Rundeck-ssh-key-type"));
+ Assert.assertEquals("public", metadata.get("Rundeck-key-type"));
}
/**
* get ssh key
*/
@Test
- @Betamax(tape = "ssh_key_get_public", mode = TapeMode.READ_ONLY)
- public void getSshKey_public() throws Exception {
+ @Betamax(tape = "key_get_public", mode = TapeMode.READ_ONLY)
+ public void getKey_public() throws Exception {
final RundeckClient client = createClient(TEST_TOKEN_7, 11);
- SSHKeyResource storageResource = client.getSshKey("ssh-key/test/example/file2.pub");
+ KeyResource storageResource = client.getKey("keys/test/example/file2.pub");
Assert.assertNotNull(storageResource);
Assert.assertFalse(storageResource.isDirectory());
Assert.assertFalse(storageResource.isPrivateKey());
Assert.assertEquals("file2.pub", storageResource.getName());
- Assert.assertEquals("ssh-key/test/example/file2.pub", storageResource.getPath());
- Assert.assertEquals("http://dignan.local:4440/api/11/storage/ssh-key/test/example/file2.pub",
+ Assert.assertEquals("keys/test/example/file2.pub", storageResource.getPath());
+ Assert.assertEquals("http://dignan.local:4440/api/11/storage/keys/test/example/file2.pub",
storageResource.getUrl());
Assert.assertEquals(0, storageResource.getDirectoryContents().size());
Map metadata = storageResource.getMetadata();
Assert.assertNotNull(metadata);
Assert.assertEquals("application/pgp-keys", metadata.get("Rundeck-content-type"));
- Assert.assertEquals("public", metadata.get("Rundeck-ssh-key-type"));
+ Assert.assertEquals("public", metadata.get("Rundeck-key-type"));
}
/**
* get ssh key
*/
@Test
- @Betamax(tape = "ssh_key_get_private", mode = TapeMode.READ_ONLY)
- public void getSshKey_private() throws Exception {
+ @Betamax(tape = "key_get_private", mode = TapeMode.READ_ONLY)
+ public void getKey_private() throws Exception {
final RundeckClient client = createClient(TEST_TOKEN_7, 11);
- SSHKeyResource storageResource = client.getSshKey("ssh-key/test/example/file1.pem");
+ KeyResource storageResource = client.getKey("keys/test/example/file1.pem");
Assert.assertNotNull(storageResource);
Assert.assertFalse(storageResource.isDirectory());
Assert.assertTrue(storageResource.isPrivateKey());
Assert.assertEquals("file1.pem", storageResource.getName());
- Assert.assertEquals("ssh-key/test/example/file1.pem", storageResource.getPath());
- Assert.assertEquals("http://dignan.local:4440/api/11/storage/ssh-key/test/example/file1.pem",
+ Assert.assertEquals("keys/test/example/file1.pem", storageResource.getPath());
+ Assert.assertEquals("http://dignan.local:4440/api/11/storage/keys/test/example/file1.pem",
storageResource.getUrl());
Assert.assertEquals(0, storageResource.getDirectoryContents().size());
Map metadata = storageResource.getMetadata();
Assert.assertNotNull(metadata);
Assert.assertEquals("application/octet-stream", metadata.get("Rundeck-content-type"));
- Assert.assertEquals("private", metadata.get("Rundeck-ssh-key-type"));
+ Assert.assertEquals("private", metadata.get("Rundeck-key-type"));
}
/**
* get ssh key data
*/
@Test
- @Betamax(tape = "ssh_key_get_data_private", mode = TapeMode.READ_ONLY)
- public void getSshKeyData_private() throws Exception {
+ @Betamax(tape = "key_get_data_private", mode = TapeMode.READ_ONLY)
+ public void getKeyData_private() throws Exception {
final RundeckClient client = createClient(TEST_TOKEN_7, 11);
File temp = File.createTempFile("test-key", ".tmp");
temp.deleteOnExit();
try {
- int data = client.getPublicSshKeyContent("ssh-key/test/example/file1.pem", temp);
+ int data = client.getPublicKeyContent("keys/test/example/file1.pem", temp);
Assert.fail("expected failure");
} catch (RundeckApiException e) {
- Assert.assertEquals("Requested SSH Key path was not a Public key: ssh-key/test/example/file1.pem",
+ Assert.assertEquals("Requested Key path was not a Public key: keys/test/example/file1.pem",
e.getMessage());
}
}
@@ -1401,72 +1401,72 @@ public class RundeckClientTest {
* get ssh key data
*/
@Test
- @Betamax(tape = "ssh_key_get_data_public", mode = TapeMode.READ_ONLY)
- public void getSshKeyData_public() throws Exception {
+ @Betamax(tape = "key_get_data_public", mode = TapeMode.READ_ONLY)
+ public void getKeyData_public() throws Exception {
final RundeckClient client = createClient(TEST_TOKEN_7, 11);
File temp = File.createTempFile("test-key", ".tmp");
temp.deleteOnExit();
- int length = client.getPublicSshKeyContent("ssh-key/test/example/file2.pub", temp);
+ int length = client.getPublicKeyContent("keys/test/example/file2.pub", temp);
Assert.assertEquals(5, length);
}
/**
* list directory
*/
@Test
- @Betamax(tape = "ssh_key_list_directory", mode = TapeMode.READ_ONLY)
- public void listSshKeyDirectory() throws Exception {
+ @Betamax(tape = "key_list_directory", mode = TapeMode.READ_ONLY)
+ public void listKeyDirectory() throws Exception {
final RundeckClient client = createClient(TEST_TOKEN_7, 11);
- List list = client.listSshKeyDirectory("ssh-key/test/example");
+ List list = client.listKeyDirectory("keys/test/example");
Assert.assertEquals(2, list.size());
- SSHKeyResource storageResource1 = list.get(0);
- SSHKeyResource storageResource2 = list.get(1);
+ KeyResource storageResource1 = list.get(0);
+ KeyResource storageResource2 = list.get(1);
Assert.assertFalse(storageResource2.isDirectory());
Assert.assertTrue(storageResource2.isPrivateKey());
Assert.assertEquals("file1.pem", storageResource2.getName());
- Assert.assertEquals("ssh-key/test/example/file1.pem", storageResource2.getPath());
- Assert.assertEquals("http://dignan.local:4440/api/11/storage/ssh-key/test/example/file1.pem", storageResource2.getUrl());
+ Assert.assertEquals("keys/test/example/file1.pem", storageResource2.getPath());
+ Assert.assertEquals("http://dignan.local:4440/api/11/storage/keys/test/example/file1.pem", storageResource2.getUrl());
Assert.assertNotNull(storageResource2.getMetadata());
Assert.assertEquals("application/octet-stream", storageResource2.getMetadata().get("Rundeck-content-type"));
- Assert.assertEquals("private", storageResource2.getMetadata().get("Rundeck-ssh-key-type"));
+ Assert.assertEquals("private", storageResource2.getMetadata().get("Rundeck-key-type"));
Assert.assertFalse(storageResource1.isDirectory());
Assert.assertFalse(storageResource1.isPrivateKey());
Assert.assertEquals("file2.pub", storageResource1.getName());
- Assert.assertEquals("ssh-key/test/example/file2.pub", storageResource1.getPath());
- Assert.assertEquals("http://dignan.local:4440/api/11/storage/ssh-key/test/example/file2.pub",
+ Assert.assertEquals("keys/test/example/file2.pub", storageResource1.getPath());
+ Assert.assertEquals("http://dignan.local:4440/api/11/storage/keys/test/example/file2.pub",
storageResource1.getUrl());
Assert.assertNotNull(storageResource1.getMetadata());
Assert.assertEquals("application/pgp-keys", storageResource1.getMetadata().get("Rundeck-content-type"));
- Assert.assertEquals("public", storageResource1.getMetadata().get("Rundeck-ssh-key-type"));
+ Assert.assertEquals("public", storageResource1.getMetadata().get("Rundeck-key-type"));
}
/**
* list root
*/
@Test
- @Betamax(tape = "ssh_key_list_root", mode = TapeMode.READ_ONLY)
- public void listSshKeyDirectoryRoot() throws Exception {
+ @Betamax(tape = "key_list_root", mode = TapeMode.READ_ONLY)
+ public void listKeyDirectoryRoot() throws Exception {
final RundeckClient client = createClient(TEST_TOKEN_7, 11);
- List list = client.listSshKeyDirectoryRoot();
+ List list = client.listKeyDirectoryRoot();
Assert.assertEquals(2, list.size());
- SSHKeyResource storageResource0 = list.get(0);
- SSHKeyResource storageResource1 = list.get(1);
+ KeyResource storageResource0 = list.get(0);
+ KeyResource storageResource1 = list.get(1);
Assert.assertFalse(storageResource0.isDirectory());
Assert.assertTrue(storageResource0.isPrivateKey());
Assert.assertEquals("test1.pem", storageResource0.getName());
- Assert.assertEquals("ssh-key/test1.pem", storageResource0.getPath());
- Assert.assertEquals("http://dignan.local:4440/api/11/storage/ssh-key/test1.pem", storageResource0.getUrl());
+ Assert.assertEquals("keys/test1.pem", storageResource0.getPath());
+ Assert.assertEquals("http://dignan.local:4440/api/11/storage/keys/test1.pem", storageResource0.getUrl());
Assert.assertNotNull(storageResource0.getMetadata());
Assert.assertEquals("application/octet-stream", storageResource0.getMetadata().get("Rundeck-content-type"));
- Assert.assertEquals("private", storageResource0.getMetadata().get("Rundeck-ssh-key-type"));
+ Assert.assertEquals("private", storageResource0.getMetadata().get("Rundeck-key-type"));
Assert.assertTrue(storageResource1.toString(), storageResource1.isDirectory());
Assert.assertEquals(null, storageResource1.getName());
- Assert.assertEquals("ssh-key/test", storageResource1.getPath());
- Assert.assertEquals("http://dignan.local:4440/api/11/storage/ssh-key/test",
+ Assert.assertEquals("keys/test", storageResource1.getPath());
+ Assert.assertEquals("http://dignan.local:4440/api/11/storage/keys/test",
storageResource1.getUrl());
Assert.assertNull(storageResource1.getMetadata());
@@ -1477,13 +1477,13 @@ public class RundeckClientTest {
* delete ssh key
*/
@Test
- @Betamax(tape = "ssh_key_delete", mode = TapeMode.READ_ONLY)
- public void deleteSshKey() throws Exception {
+ @Betamax(tape = "key_delete", mode = TapeMode.READ_ONLY)
+ public void deleteKey() throws Exception {
final RundeckClient client = createClient(TEST_TOKEN_7, 11);
- client.deleteSshKey("ssh-key/test/example/file2.pub");
+ client.deleteKey("keys/test/example/file2.pub");
try {
- client.getSshKey("ssh-key/test/example/file2.pub");
+ client.getKey("keys/test/example/file2.pub");
Assert.fail("expected failure");
} catch (RundeckApiException.RundeckApiHttpStatusException e) {
Assert.assertEquals(404,e.getStatusCode());
diff --git a/src/test/resources/betamax/tapes/ssh_key_delete.yaml b/src/test/resources/betamax/tapes/key_delete.yaml
similarity index 86%
rename from src/test/resources/betamax/tapes/ssh_key_delete.yaml
rename to src/test/resources/betamax/tapes/key_delete.yaml
index fd46eae..b52ed7f 100644
--- a/src/test/resources/betamax/tapes/ssh_key_delete.yaml
+++ b/src/test/resources/betamax/tapes/key_delete.yaml
@@ -4,7 +4,7 @@ interactions:
- recorded: 2014-04-04T23:16:02.256Z
request:
method: DELETE
- uri: http://rundeck.local:4440/api/11/storage/ssh-key/test/example/file2.pub
+ uri: http://rundeck.local:4440/api/11/storage/keys/test/example/file2.pub
headers:
Host: rundeck.local:4440
Proxy-Connection: Keep-Alive
@@ -20,7 +20,7 @@ interactions:
- recorded: 2014-04-04T23:16:02.372Z
request:
method: GET
- uri: http://rundeck.local:4440/api/11/storage/ssh-key/test/example/file2.pub
+ uri: http://rundeck.local:4440/api/11/storage/keys/test/example/file2.pub
headers:
Accept: text/xml
Host: rundeck.local:4440
diff --git a/src/test/resources/betamax/tapes/ssh_key_get_data_private.yaml b/src/test/resources/betamax/tapes/key_get_data_private.yaml
similarity index 54%
rename from src/test/resources/betamax/tapes/ssh_key_get_data_private.yaml
rename to src/test/resources/betamax/tapes/key_get_data_private.yaml
index e5e742b..ef0f58f 100644
--- a/src/test/resources/betamax/tapes/ssh_key_get_data_private.yaml
+++ b/src/test/resources/betamax/tapes/key_get_data_private.yaml
@@ -4,7 +4,7 @@ interactions:
- recorded: 2014-04-04T19:50:59.155Z
request:
method: GET
- uri: http://rundeck.local:4440/api/11/storage/ssh-key/test/example/file1.pem
+ uri: http://rundeck.local:4440/api/11/storage/keys/test/example/file1.pem
headers:
Accept: application/pgp-keys
Host: rundeck.local:4440
@@ -19,4 +19,5 @@ interactions:
Server: Jetty(7.6.0.v20120127)
Set-Cookie: JSESSIONID=1gzu37lkjr0fitxhf5fgkgsfu;Path=/
body: !!binary |-
- eyJwYXRoIjoic3NoLWtleS90ZXN0L2V4YW1wbGUvZmlsZTEucGVtIiwidHlwZSI6ImZpbGUiLCJuYW1lIjoiZmlsZTEucGVtIiwidXJsIjoiaHR0cDovL2RpZ25hbi5sb2NhbDo0NDQwL2FwaS8xMS9zdG9yYWdlL3NzaC1rZXkvdGVzdC9leGFtcGxlL2ZpbGUxLnBlbSIsIm1ldGEiOnsiUnVuZGVjay1jb250ZW50LXR5cGUiOiJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0iLCJSdW5kZWNrLWNvbnRlbnQtc2l6ZSI6IjUiLCJSdW5kZWNrLWNvbnRlbnQtbWFzayI6ImNvbnRlbnQiLCJSdW5kZWNrLXNzaC1rZXktdHlwZSI6InByaXZhdGUifX0=
+ eyJwYXRoIjoia2V5cy90ZXN0L2V4YW1wbGUvZmlsZTEucGVtIiwidHlwZSI6ImZpbGUiLCJuYW1lIjoiZmlsZTEucGVtIiwidXJsIjoiaHR0cDovL2RpZ25hbi5sb2NhbDo0NDQwL2FwaS8xMS9zdG9yYWdlL2tleXMvdGVzdC9leGFtcGxlL2ZpbGUxLnBlbSIsIm1ldGEiOnsiUnVuZGVjay1jb250ZW50LXR5cGUiOiJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0iLCJSdW5kZWNrLWNvbnRlbnQtc2l6ZSI6IjUiLCJSdW5kZWNrLWNvbnRlbnQtbWFzayI6ImNvbnRlbnQiLCJSdW5kZWNrLWtleS10eXBlIjoicHJpdmF0ZSJ9fQo=
+
diff --git a/src/test/resources/betamax/tapes/ssh_key_get_data_public.yaml b/src/test/resources/betamax/tapes/key_get_data_public.yaml
similarity index 88%
rename from src/test/resources/betamax/tapes/ssh_key_get_data_public.yaml
rename to src/test/resources/betamax/tapes/key_get_data_public.yaml
index 1874e71..054599f 100644
--- a/src/test/resources/betamax/tapes/ssh_key_get_data_public.yaml
+++ b/src/test/resources/betamax/tapes/key_get_data_public.yaml
@@ -4,7 +4,7 @@ interactions:
- recorded: 2014-04-04T20:20:44.331Z
request:
method: GET
- uri: http://rundeck.local:4440/api/11/storage/ssh-key/test/example/file2.pub
+ uri: http://rundeck.local:4440/api/11/storage/keys/test/example/file2.pub
headers:
Accept: application/pgp-keys
Host: rundeck.local:4440
diff --git a/src/test/resources/betamax/tapes/key_get_private.yaml b/src/test/resources/betamax/tapes/key_get_private.yaml
new file mode 100644
index 0000000..57802a8
--- /dev/null
+++ b/src/test/resources/betamax/tapes/key_get_private.yaml
@@ -0,0 +1,23 @@
+!tape
+name: ssh_key_get_private
+interactions:
+- recorded: 2014-04-04T19:47:29.880Z
+ request:
+ method: GET
+ uri: http://rundeck.local:4440/api/11/storage/keys/test/example/file1.pem
+ headers:
+ Accept: text/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
+ response:
+ status: 200
+ headers:
+ Content-Type: application/xml;charset=utf-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=nc5p0he3nw19e4gegidc4bs7;Path=/
+ body: !!binary |-
+ PHJlc291cmNlIHBhdGg9J2tleXMvdGVzdC9leGFtcGxlL2ZpbGUxLnBlbScgdHlwZT0nZmlsZScgdXJsPSdodHRwOi8vZGlnbmFuLmxvY2FsOjQ0NDAvYXBpLzExL3N0b3JhZ2Uva2V5cy90ZXN0L2V4YW1wbGUvZmlsZTEucGVtJyBuYW1lPSdmaWxlMS5wZW0nPjxyZXNvdXJjZS1tZXRhPjxSdW5kZWNrLWNvbnRlbnQtdHlwZT5hcHBsaWNhdGlvbi9vY3RldC1zdHJlYW08L1J1bmRlY2stY29udGVudC10eXBlPjxSdW5kZWNrLWNvbnRlbnQtc2l6ZT41PC9SdW5kZWNrLWNvbnRlbnQtc2l6ZT48UnVuZGVjay1jb250ZW50LW1hc2s+Y29udGVudDwvUnVuZGVjay1jb250ZW50LW1hc2s+PFJ1bmRlY2sta2V5LXR5cGU+cHJpdmF0ZTwvUnVuZGVjay1rZXktdHlwZT48L3Jlc291cmNlLW1ldGE+PC9yZXNvdXJjZT4K
+
diff --git a/src/test/resources/betamax/tapes/ssh_key_get_public.yaml b/src/test/resources/betamax/tapes/key_get_public.yaml
similarity index 50%
rename from src/test/resources/betamax/tapes/ssh_key_get_public.yaml
rename to src/test/resources/betamax/tapes/key_get_public.yaml
index 8bede8d..32c2510 100644
--- a/src/test/resources/betamax/tapes/ssh_key_get_public.yaml
+++ b/src/test/resources/betamax/tapes/key_get_public.yaml
@@ -4,7 +4,7 @@ interactions:
- recorded: 2014-04-04T19:47:29.626Z
request:
method: GET
- uri: http://rundeck.local:4440/api/11/storage/ssh-key/test/example/file2.pub
+ uri: http://rundeck.local:4440/api/11/storage/keys/test/example/file2.pub
headers:
Accept: text/xml
Host: rundeck.local:4440
@@ -19,4 +19,5 @@ interactions:
Server: Jetty(7.6.0.v20120127)
Set-Cookie: JSESSIONID=r6p6fl87ftrb1mkwwi0pcak5i;Path=/
body: !!binary |-
- PHJlc291cmNlIHBhdGg9J3NzaC1rZXkvdGVzdC9leGFtcGxlL2ZpbGUyLnB1YicgdHlwZT0nZmlsZScgdXJsPSdodHRwOi8vZGlnbmFuLmxvY2FsOjQ0NDAvYXBpLzExL3N0b3JhZ2Uvc3NoLWtleS90ZXN0L2V4YW1wbGUvZmlsZTIucHViJyBuYW1lPSdmaWxlMi5wdWInPjxyZXNvdXJjZS1tZXRhPjxSdW5kZWNrLWNvbnRlbnQtdHlwZT5hcHBsaWNhdGlvbi9wZ3Ata2V5czwvUnVuZGVjay1jb250ZW50LXR5cGU+PFJ1bmRlY2stY29udGVudC1zaXplPjU8L1J1bmRlY2stY29udGVudC1zaXplPjxSdW5kZWNrLXNzaC1rZXktdHlwZT5wdWJsaWM8L1J1bmRlY2stc3NoLWtleS10eXBlPjwvcmVzb3VyY2UtbWV0YT48L3Jlc291cmNlPg==
+ PHJlc291cmNlIHBhdGg9J2tleXMvdGVzdC9leGFtcGxlL2ZpbGUyLnB1YicgdHlwZT0nZmlsZScgdXJsPSdodHRwOi8vZGlnbmFuLmxvY2FsOjQ0NDAvYXBpLzExL3N0b3JhZ2Uva2V5cy90ZXN0L2V4YW1wbGUvZmlsZTIucHViJyBuYW1lPSdmaWxlMi5wdWInPjxyZXNvdXJjZS1tZXRhPjxSdW5kZWNrLWNvbnRlbnQtdHlwZT5hcHBsaWNhdGlvbi9wZ3Ata2V5czwvUnVuZGVjay1jb250ZW50LXR5cGU+PFJ1bmRlY2stY29udGVudC1zaXplPjU8L1J1bmRlY2stY29udGVudC1zaXplPjxSdW5kZWNrLWtleS10eXBlPnB1YmxpYzwvUnVuZGVjay1rZXktdHlwZT48L3Jlc291cmNlLW1ldGE+PC9yZXNvdXJjZT4N
+
diff --git a/src/test/resources/betamax/tapes/key_list_directory.yaml b/src/test/resources/betamax/tapes/key_list_directory.yaml
new file mode 100644
index 0000000..fb4c6f6
--- /dev/null
+++ b/src/test/resources/betamax/tapes/key_list_directory.yaml
@@ -0,0 +1,21 @@
+!tape
+name: key_list_directory
+interactions:
+- recorded: 2014-04-04T20:33:07.968Z
+ request:
+ method: GET
+ uri: http://rundeck.local:4440/api/11/storage/keys/test/example
+ headers:
+ Accept: text/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
+ response:
+ status: 200
+ headers:
+ Content-Type: text/html;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=1stwtoatsosy91ca0gcrzde698;Path=/
+ body: application/pgp-keys 5 public application/octet-stream 5 content private
diff --git a/src/test/resources/betamax/tapes/key_list_root.yaml b/src/test/resources/betamax/tapes/key_list_root.yaml
new file mode 100644
index 0000000..b040c3e
--- /dev/null
+++ b/src/test/resources/betamax/tapes/key_list_root.yaml
@@ -0,0 +1,21 @@
+!tape
+name: key_list_root
+interactions:
+- recorded: 2014-04-04T20:41:16.501Z
+ request:
+ method: GET
+ uri: http://rundeck.local:4440/api/11/storage/keys/
+ headers:
+ Accept: text/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
+ response:
+ status: 200
+ headers:
+ Content-Type: text/html;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=5sj36vytg4y1182mziim4868b;Path=/
+ body: application/octet-stream 1679 content private
diff --git a/src/test/resources/betamax/tapes/ssh_key_store_private.yaml b/src/test/resources/betamax/tapes/key_store_private.yaml
similarity index 50%
rename from src/test/resources/betamax/tapes/ssh_key_store_private.yaml
rename to src/test/resources/betamax/tapes/key_store_private.yaml
index 6ef2def..1a5d0b0 100644
--- a/src/test/resources/betamax/tapes/ssh_key_store_private.yaml
+++ b/src/test/resources/betamax/tapes/key_store_private.yaml
@@ -4,7 +4,7 @@ interactions:
- recorded: 2014-04-04T19:30:35.367Z
request:
method: POST
- uri: http://rundeck.local:4440/api/11/storage/ssh-key/test/example/file1.pem
+ uri: http://rundeck.local:4440/api/11/storage/keys/test/example/file1.pem
headers:
Accept: text/xml
Content-Length: '5'
@@ -22,4 +22,5 @@ interactions:
Server: Jetty(7.6.0.v20120127)
Set-Cookie: JSESSIONID=ktmwc4h53xfud6v2ch67x5p9;Path=/
body: !!binary |-
- PHJlc291cmNlIHBhdGg9J3NzaC1rZXkvdGVzdC9leGFtcGxlL2ZpbGUxLnBlbScgdHlwZT0nZmlsZScgdXJsPSdodHRwOi8vZGlnbmFuLmxvY2FsOjQ0NDAvYXBpLzExL3N0b3JhZ2Uvc3NoLWtleS90ZXN0L2V4YW1wbGUvZmlsZTEucGVtJyBuYW1lPSdmaWxlMS5wZW0nPjxyZXNvdXJjZS1tZXRhPjxSdW5kZWNrLWNvbnRlbnQtdHlwZT5hcHBsaWNhdGlvbi9vY3RldC1zdHJlYW08L1J1bmRlY2stY29udGVudC10eXBlPjxSdW5kZWNrLWNvbnRlbnQtc2l6ZT41PC9SdW5kZWNrLWNvbnRlbnQtc2l6ZT48UnVuZGVjay1jb250ZW50LW1hc2s+Y29udGVudDwvUnVuZGVjay1jb250ZW50LW1hc2s+PFJ1bmRlY2stc3NoLWtleS10eXBlPnByaXZhdGU8L1J1bmRlY2stc3NoLWtleS10eXBlPjwvcmVzb3VyY2UtbWV0YT48L3Jlc291cmNlPg==
+ PHJlc291cmNlIHBhdGg9J2tleXMvdGVzdC9leGFtcGxlL2ZpbGUxLnBlbScgdHlwZT0nZmlsZScgdXJsPSdodHRwOi8vZGlnbmFuLmxvY2FsOjQ0NDAvYXBpLzExL3N0b3JhZ2Uva2V5cy90ZXN0L2V4YW1wbGUvZmlsZTEucGVtJyBuYW1lPSdmaWxlMS5wZW0nPjxyZXNvdXJjZS1tZXRhPjxSdW5kZWNrLWNvbnRlbnQtdHlwZT5hcHBsaWNhdGlvbi9vY3RldC1zdHJlYW08L1J1bmRlY2stY29udGVudC10eXBlPjxSdW5kZWNrLWNvbnRlbnQtc2l6ZT41PC9SdW5kZWNrLWNvbnRlbnQtc2l6ZT48UnVuZGVjay1jb250ZW50LW1hc2s+Y29udGVudDwvUnVuZGVjay1jb250ZW50LW1hc2s+PFJ1bmRlY2sta2V5LXR5cGU+cHJpdmF0ZTwvUnVuZGVjay1rZXktdHlwZT48L3Jlc291cmNlLW1ldGE+PC9yZXNvdXJjZT4N
+
diff --git a/src/test/resources/betamax/tapes/ssh_key_store_public.yaml b/src/test/resources/betamax/tapes/key_store_public.yaml
similarity index 53%
rename from src/test/resources/betamax/tapes/ssh_key_store_public.yaml
rename to src/test/resources/betamax/tapes/key_store_public.yaml
index 8a1b18a..fdd7638 100644
--- a/src/test/resources/betamax/tapes/ssh_key_store_public.yaml
+++ b/src/test/resources/betamax/tapes/key_store_public.yaml
@@ -4,7 +4,7 @@ interactions:
- recorded: 2014-04-04T19:34:02.683Z
request:
method: POST
- uri: http://rundeck.local:4440/api/11/storage/ssh-key/test/example/file2.pub
+ uri: http://rundeck.local:4440/api/11/storage/keys/test/example/file2.pub
headers:
Accept: text/xml
Content-Length: '5'
@@ -22,4 +22,5 @@ interactions:
Server: Jetty(7.6.0.v20120127)
Set-Cookie: JSESSIONID=2l3g8m0tvwef19jn2bu23bzk6;Path=/
body: !!binary |-
- PHJlc291cmNlIHBhdGg9J3NzaC1rZXkvdGVzdC9leGFtcGxlL2ZpbGUyLnB1YicgdHlwZT0nZmlsZScgdXJsPSdodHRwOi8vZGlnbmFuLmxvY2FsOjQ0NDAvYXBpLzExL3N0b3JhZ2Uvc3NoLWtleS90ZXN0L2V4YW1wbGUvZmlsZTIucHViJyBuYW1lPSdmaWxlMi5wdWInPjxyZXNvdXJjZS1tZXRhPjxSdW5kZWNrLWNvbnRlbnQtdHlwZT5hcHBsaWNhdGlvbi9wZ3Ata2V5czwvUnVuZGVjay1jb250ZW50LXR5cGU+PFJ1bmRlY2stY29udGVudC1zaXplPjU8L1J1bmRlY2stY29udGVudC1zaXplPjxSdW5kZWNrLXNzaC1rZXktdHlwZT5wdWJsaWM8L1J1bmRlY2stc3NoLWtleS10eXBlPjwvcmVzb3VyY2UtbWV0YT48L3Jlc291cmNlPg==
+ PHJlc291cmNlIHBhdGg9J2tleXMvdGVzdC9leGFtcGxlL2ZpbGUyLnB1YicgdHlwZT0nZmlsZScgdXJsPSdodHRwOi8vZGlnbmFuLmxvY2FsOjQ0NDAvYXBpLzExL3N0b3JhZ2Uva2V5cy90ZXN0L2V4YW1wbGUvZmlsZTIucHViJyBuYW1lPSdmaWxlMi5wdWInPjxyZXNvdXJjZS1tZXRhPjxSdW5kZWNrLWNvbnRlbnQtdHlwZT5hcHBsaWNhdGlvbi9wZ3Ata2V5czwvUnVuZGVjay1jb250ZW50LXR5cGU+PFJ1bmRlY2stY29udGVudC1zaXplPjU8L1J1bmRlY2stY29udGVudC1zaXplPjxSdW5kZWNrLWtleS10eXBlPnB1YmxpYzwvUnVuZGVjay1rZXktdHlwZT48L3Jlc291cmNlLW1ldGE+PC9yZXNvdXJjZT4K
+
diff --git a/src/test/resources/betamax/tapes/ssh_key_get_private.yaml b/src/test/resources/betamax/tapes/ssh_key_get_private.yaml
deleted file mode 100644
index fa0ff2c..0000000
--- a/src/test/resources/betamax/tapes/ssh_key_get_private.yaml
+++ /dev/null
@@ -1,22 +0,0 @@
-!tape
-name: ssh_key_get_private
-interactions:
-- recorded: 2014-04-04T19:47:29.880Z
- request:
- method: GET
- uri: http://rundeck.local:4440/api/11/storage/ssh-key/test/example/file1.pem
- headers:
- Accept: text/xml
- Host: rundeck.local:4440
- Proxy-Connection: Keep-Alive
- User-Agent: RunDeck API Java Client 11
- X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
- response:
- status: 200
- headers:
- Content-Type: application/xml;charset=utf-8
- Expires: Thu, 01 Jan 1970 00:00:00 GMT
- Server: Jetty(7.6.0.v20120127)
- Set-Cookie: JSESSIONID=nc5p0he3nw19e4gegidc4bs7;Path=/
- body: !!binary |-
- PHJlc291cmNlIHBhdGg9J3NzaC1rZXkvdGVzdC9leGFtcGxlL2ZpbGUxLnBlbScgdHlwZT0nZmlsZScgdXJsPSdodHRwOi8vZGlnbmFuLmxvY2FsOjQ0NDAvYXBpLzExL3N0b3JhZ2Uvc3NoLWtleS90ZXN0L2V4YW1wbGUvZmlsZTEucGVtJyBuYW1lPSdmaWxlMS5wZW0nPjxyZXNvdXJjZS1tZXRhPjxSdW5kZWNrLWNvbnRlbnQtdHlwZT5hcHBsaWNhdGlvbi9vY3RldC1zdHJlYW08L1J1bmRlY2stY29udGVudC10eXBlPjxSdW5kZWNrLWNvbnRlbnQtc2l6ZT41PC9SdW5kZWNrLWNvbnRlbnQtc2l6ZT48UnVuZGVjay1jb250ZW50LW1hc2s+Y29udGVudDwvUnVuZGVjay1jb250ZW50LW1hc2s+PFJ1bmRlY2stc3NoLWtleS10eXBlPnByaXZhdGU8L1J1bmRlY2stc3NoLWtleS10eXBlPjwvcmVzb3VyY2UtbWV0YT48L3Jlc291cmNlPg==
diff --git a/src/test/resources/betamax/tapes/ssh_key_list_directory.yaml b/src/test/resources/betamax/tapes/ssh_key_list_directory.yaml
deleted file mode 100644
index e49f941..0000000
--- a/src/test/resources/betamax/tapes/ssh_key_list_directory.yaml
+++ /dev/null
@@ -1,21 +0,0 @@
-!tape
-name: ssh_key_list_directory
-interactions:
-- recorded: 2014-04-04T20:33:07.968Z
- request:
- method: GET
- uri: http://rundeck.local:4440/api/11/storage/ssh-key/test/example
- headers:
- Accept: text/xml
- Host: rundeck.local:4440
- Proxy-Connection: Keep-Alive
- User-Agent: RunDeck API Java Client 11
- X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
- response:
- status: 200
- headers:
- Content-Type: text/html;charset=UTF-8
- Expires: Thu, 01 Jan 1970 00:00:00 GMT
- Server: Jetty(7.6.0.v20120127)
- Set-Cookie: JSESSIONID=1stwtoatsosy91ca0gcrzde698;Path=/
- body: application/pgp-keys 5 public application/octet-stream 5 content private
diff --git a/src/test/resources/betamax/tapes/ssh_key_list_root.yaml b/src/test/resources/betamax/tapes/ssh_key_list_root.yaml
deleted file mode 100644
index dcefe5e..0000000
--- a/src/test/resources/betamax/tapes/ssh_key_list_root.yaml
+++ /dev/null
@@ -1,21 +0,0 @@
-!tape
-name: ssh_key_list_root
-interactions:
-- recorded: 2014-04-04T20:41:16.501Z
- request:
- method: GET
- uri: http://rundeck.local:4440/api/11/storage/ssh-key/
- headers:
- Accept: text/xml
- Host: rundeck.local:4440
- Proxy-Connection: Keep-Alive
- User-Agent: RunDeck API Java Client 11
- X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
- response:
- status: 200
- headers:
- Content-Type: text/html;charset=UTF-8
- Expires: Thu, 01 Jan 1970 00:00:00 GMT
- Server: Jetty(7.6.0.v20120127)
- Set-Cookie: JSESSIONID=5sj36vytg4y1182mziim4868b;Path=/
- body: application/octet-stream 1679 content private
From 0191bd34ff63d722271170b632241006168432af Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Wed, 23 Apr 2014 16:37:11 -0700
Subject: [PATCH 55/89] Update status and changes docs
---
src/changes/changes.xml | 16 ++++++++++++++++
src/site/confluence/status.confluence | 8 ++++----
2 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index ba52cb2..825c4ca 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -22,6 +22,22 @@
Vincent Behar
+
+ Project creation
+ Get Project configuration
+ Set Project configuration
+ Get/Set Project configuration keys
+ Delete project
+ Export project archive
+ Import project archive
+ Key file upload
+ Key file delete
+ Key file list
+ Key file get
+ API Token create
+ API Token list
+ API Token delete
+
Execution State - Retrieve workflow step and node state information
diff --git a/src/site/confluence/status.confluence b/src/site/confluence/status.confluence
index 3042fa8..39a2185 100644
--- a/src/site/confluence/status.confluence
+++ b/src/site/confluence/status.confluence
@@ -106,10 +106,10 @@ h2. RunDeck API version 11
* Delete project - OK
* Export project archive - OK
* Import project archive - OK
-* SSH Key upload - OK
-* SSH Key delete - OK
-* SSH Key list - OK
-* SSH Key get - OK
+* Key file upload - OK
+* Key file delete - OK
+* Key file list - OK
+* Key file get - OK
* API Token create - OK
* API Token list - OK
* API Token delete - OK
From 7146aca1297fcb1f4d186b35d02800df56185ce7 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Wed, 23 Apr 2014 17:51:51 -0700
Subject: [PATCH 56/89] Update version to 11.0-SNAPSHOT
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index d284be1..eebf968 100644
--- a/pom.xml
+++ b/pom.xml
@@ -27,7 +27,7 @@
org.rundeck
rundeck-api-java-client
- 10.1-SNAPSHOT
+ 11.0-SNAPSHOT
jar
RunDeck API - Java Client
Java client for the RunDeck REST API
From d3cad78f3d90a0eb00e8c0883e7d1336b9561354 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Wed, 23 Apr 2014 18:43:00 -0700
Subject: [PATCH 57/89] [maven-release-plugin] prepare release
rundeck-api-java-client-11.0-redo3
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index eebf968..a39e4f7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -27,7 +27,7 @@
org.rundeck
rundeck-api-java-client
- 11.0-SNAPSHOT
+ 11.0
jar
RunDeck API - Java Client
Java client for the RunDeck REST API
From 7b6259b66b011c34cbc014e67cdc1a8882c98a22 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Wed, 23 Apr 2014 18:43:04 -0700
Subject: [PATCH 58/89] [maven-release-plugin] prepare for next development
iteration
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index a39e4f7..722956b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -27,7 +27,7 @@
org.rundeck
rundeck-api-java-client
- 11.0
+ 11.1-SNAPSHOT
jar
RunDeck API - Java Client
Java client for the RunDeck REST API
From bbe599b915fa662a088cf559579f165a33c45b22 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Thu, 6 Nov 2014 08:49:25 -0800
Subject: [PATCH 59/89] Add todo
---
src/site/confluence/status.confluence | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/site/confluence/status.confluence b/src/site/confluence/status.confluence
index 39a2185..c161cf4 100644
--- a/src/site/confluence/status.confluence
+++ b/src/site/confluence/status.confluence
@@ -113,3 +113,11 @@ h2. RunDeck API version 11
* API Token create - OK
* API Token list - OK
* API Token delete - OK
+
+h2. Rundeck API version 12
+
+[Documentation of the RunDeck API version 12|http://rundeck.org/2.2.0/api/index.html]
+
+* Bulk delete executions - TBD
+* Delete execution - TBD
+* Delete all executions for a job - TBD
From a7c0c22699475fd31ceb283b8e35e5d516f7135f Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Thu, 6 Nov 2014 09:32:30 -0800
Subject: [PATCH 60/89] Add bulk Delete executions endpoint
---
.../java/org/rundeck/api/RundeckClient.java | 28 ++++++-
.../api/domain/DeleteExecutionsResponse.java | 84 +++++++++++++++++++
.../generator/DeleteExecutionsGenerator.java | 38 +++++++++
.../DeleteExecutionsResponseParser.java | 52 ++++++++++++
.../org/rundeck/api/RundeckClientTest.java | 82 ++++++++++++++++++
.../tapes/delete_executions_mixed.yaml | 26 ++++++
.../tapes/delete_executions_success.yaml | 26 ++++++
.../tapes/delete_executions_unauthorized.yaml | 26 ++++++
8 files changed, 361 insertions(+), 1 deletion(-)
create mode 100644 src/main/java/org/rundeck/api/domain/DeleteExecutionsResponse.java
create mode 100644 src/main/java/org/rundeck/api/generator/DeleteExecutionsGenerator.java
create mode 100644 src/main/java/org/rundeck/api/parser/DeleteExecutionsResponseParser.java
create mode 100644 src/test/resources/betamax/tapes/delete_executions_mixed.yaml
create mode 100644 src/test/resources/betamax/tapes/delete_executions_success.yaml
create mode 100644 src/test/resources/betamax/tapes/delete_executions_unauthorized.yaml
diff --git a/src/main/java/org/rundeck/api/RundeckClient.java b/src/main/java/org/rundeck/api/RundeckClient.java
index 8462dba..93ced66 100644
--- a/src/main/java/org/rundeck/api/RundeckClient.java
+++ b/src/main/java/org/rundeck/api/RundeckClient.java
@@ -23,6 +23,7 @@ import org.rundeck.api.RundeckApiException.RundeckApiLoginException;
import org.rundeck.api.RundeckApiException.RundeckApiTokenException;
import org.rundeck.api.domain.*;
import org.rundeck.api.domain.RundeckExecution.ExecutionStatus;
+import org.rundeck.api.generator.DeleteExecutionsGenerator;
import org.rundeck.api.generator.ProjectConfigGenerator;
import org.rundeck.api.generator.ProjectConfigPropertyGenerator;
import org.rundeck.api.generator.ProjectGenerator;
@@ -95,6 +96,7 @@ public class RundeckClient implements Serializable {
V9(9),
V10(10),
V11(11),
+ V12(12),
;
private int versionNumber;
@@ -108,7 +110,7 @@ public class RundeckClient implements Serializable {
}
}
/** Version of the API supported */
- public static final transient int API_VERSION = Version.V11.getVersionNumber();
+ public static final transient int API_VERSION = Version.V12.getVersionNumber();
private static final String API = "/api/";
@@ -1643,6 +1645,30 @@ public class RundeckClient implements Serializable {
return new ApiCall(this).get(apiPath, new AbortParser(rootXpath()+"/abort"));
}
+ /**
+ * Delete a set of executions, identified by the given IDs
+ *
+ * @param executionIds set of identifiers for the executions - mandatory
+ * @return a {@link RundeckExecution} 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 DeleteExecutionsResponse deleteExecutions(Set executionIds)
+ throws RundeckApiException, RundeckApiLoginException,
+ RundeckApiTokenException, IllegalArgumentException
+ {
+ AssertUtil.notNull(executionIds, "executionIds is mandatory to abort an execution !");
+ final ApiPathBuilder apiPath = new ApiPathBuilder("/executions/delete").xml(
+ new DeleteExecutionsGenerator(executionIds)
+ );
+ return new ApiCall(this).post(
+ apiPath,
+ new DeleteExecutionsResponseParser( rootXpath() + "/deleteExecutions")
+ );
+ }
+
/*
* History
*/
diff --git a/src/main/java/org/rundeck/api/domain/DeleteExecutionsResponse.java b/src/main/java/org/rundeck/api/domain/DeleteExecutionsResponse.java
new file mode 100644
index 0000000..6d1f53b
--- /dev/null
+++ b/src/main/java/org/rundeck/api/domain/DeleteExecutionsResponse.java
@@ -0,0 +1,84 @@
+package org.rundeck.api.domain;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * DeleteExecutionsResponse is ...
+ *
+ * @author Greg Schueler
+ * @since 2014-11-06
+ */
+public class DeleteExecutionsResponse implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private int failedCount;
+ private int successCount;
+ private boolean allsuccessful;
+ private int requestCount;
+ private List failures;
+
+ public int getFailedCount() {
+ return failedCount;
+ }
+
+ public void setFailedCount(final int failedCount) {
+ this.failedCount = failedCount;
+ }
+
+ public int getSuccessCount() {
+ return successCount;
+ }
+
+ public void setSuccessCount(final int successCount) {
+ this.successCount = successCount;
+ }
+
+ public boolean isAllsuccessful() {
+ return allsuccessful;
+ }
+
+ public void setAllsuccessful(final boolean allsuccessful) {
+ this.allsuccessful = allsuccessful;
+ }
+
+ public int getRequestCount() {
+ return requestCount;
+ }
+
+ public void setRequestCount(final int requestCount) {
+ this.requestCount = requestCount;
+ }
+
+ public List getFailures() {
+ return failures;
+ }
+
+ public void setFailures(final List failures) {
+ this.failures = failures;
+ }
+
+ public static class DeleteFailure implements Serializable{
+
+ private static final long serialVersionUID = 1L;
+ private Long executionId;
+ private String message;
+
+ public Long getExecutionId() {
+ return executionId;
+ }
+
+ public void setExecutionId(final Long executionId) {
+ this.executionId = executionId;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(final String message) {
+ this.message = message;
+ }
+ }
+}
diff --git a/src/main/java/org/rundeck/api/generator/DeleteExecutionsGenerator.java b/src/main/java/org/rundeck/api/generator/DeleteExecutionsGenerator.java
new file mode 100644
index 0000000..8efd2bf
--- /dev/null
+++ b/src/main/java/org/rundeck/api/generator/DeleteExecutionsGenerator.java
@@ -0,0 +1,38 @@
+package org.rundeck.api.generator;
+
+import org.dom4j.DocumentFactory;
+import org.dom4j.Element;
+import org.rundeck.api.domain.ProjectConfig;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * DeleteExecutionsGenerator is ...
+ *
+ * @author Greg Schueler
+ * @since 2014-11-06
+ */
+public class DeleteExecutionsGenerator extends BaseDocGenerator {
+ private Set executionIds;
+
+ public DeleteExecutionsGenerator(final Set executionIds) {
+ this.executionIds = executionIds;
+ }
+
+ @Override public Element generateXmlElement() {
+ Element rootElem = DocumentFactory.getInstance().createElement("executions");
+ for (Long executionId : executionIds) {
+ rootElem.addElement("execution").addAttribute("id", Long.toString(executionId));
+ }
+ return rootElem;
+ }
+
+ public Set getExecutionIds() {
+ return executionIds;
+ }
+
+ public void setExecutionIds(final Set executionIds) {
+ this.executionIds = executionIds;
+ }
+}
diff --git a/src/main/java/org/rundeck/api/parser/DeleteExecutionsResponseParser.java b/src/main/java/org/rundeck/api/parser/DeleteExecutionsResponseParser.java
new file mode 100644
index 0000000..c3de8af
--- /dev/null
+++ b/src/main/java/org/rundeck/api/parser/DeleteExecutionsResponseParser.java
@@ -0,0 +1,52 @@
+package org.rundeck.api.parser;
+
+import org.dom4j.Node;
+import org.rundeck.api.domain.DeleteExecutionsResponse;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * DeleteExecutionsResponseParser is ...
+ *
+ * @author Greg Schueler
+ * @since 2014-11-06
+ */
+public class DeleteExecutionsResponseParser implements XmlNodeParser {
+ private String xpath;
+
+ public DeleteExecutionsResponseParser(final String xpath) {
+ this.xpath = xpath;
+ }
+
+ @Override public DeleteExecutionsResponse parseXmlNode(final Node node) {
+ final Node baseNode = xpath != null ? node.selectSingleNode(xpath) : node;
+
+ final DeleteExecutionsResponse response = new DeleteExecutionsResponse();
+ response.setAllsuccessful(Boolean.parseBoolean(baseNode.valueOf("@allsuccessful")));
+ response.setRequestCount(Integer.parseInt(baseNode.valueOf("@requestCount")));
+ response.setSuccessCount(Integer.parseInt(baseNode.valueOf("successful/@count")));
+
+ final Node failedNode = baseNode.selectSingleNode("failed");
+ //parse failures
+ final List failures = new ArrayList
+ ();
+ int failedCount = 0;
+ if (null != failedNode) {
+ failedCount = Integer.parseInt(baseNode.valueOf("failed/@count"));
+ final List list = baseNode.selectNodes("failed/execution");
+
+ for (final Object o : list) {
+ final Node execNode = (Node) o;
+ final DeleteExecutionsResponse.DeleteFailure deleteFailure =
+ new DeleteExecutionsResponse.DeleteFailure();
+ deleteFailure.setExecutionId(Long.parseLong(execNode.valueOf("@id")));
+ deleteFailure.setMessage(execNode.valueOf("@message"));
+ failures.add(deleteFailure);
+ }
+ }
+ response.setFailedCount(failedCount);
+ response.setFailures(failures);
+ return response;
+ }
+}
diff --git a/src/test/java/org/rundeck/api/RundeckClientTest.java b/src/test/java/org/rundeck/api/RundeckClientTest.java
index fb01b80..27fa3eb 100644
--- a/src/test/java/org/rundeck/api/RundeckClientTest.java
+++ b/src/test/java/org/rundeck/api/RundeckClientTest.java
@@ -56,6 +56,7 @@ public class RundeckClientTest {
public static final String TEST_TOKEN_5 = "C3O6d5O98Kr6Dpv71sdE4ERdCuU12P6d";
public static final String TEST_TOKEN_6 = "Do4d3NUD5DKk21DR4sNK755RcPk618vn";
public static final String TEST_TOKEN_7 = "8Dp9op111ER6opsDRkddvE86K9sE499s";
+ public static final String TEST_TOKEN_8 = "GG7uj1y6UGahOs7QlmeN2sIwz1Y2j7zI";
@Rule
public Recorder recorder = new Recorder();
@@ -1490,6 +1491,87 @@ public class RundeckClientTest {
}
}
+ /**
+ * delete executions with failure
+ */
+ @Test
+ @Betamax(tape = "delete_executions_unauthorized", mode = TapeMode.READ_ONLY)
+ public void deleteExecutionsUnauthorized() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_8, 12);
+ final DeleteExecutionsResponse response = client.deleteExecutions(
+ new HashSet() {{
+ add(640L);
+ add(641L);
+ }}
+ );
+ Assert.assertEquals(2, response.getRequestCount());
+ Assert.assertEquals(0, response.getSuccessCount());
+ Assert.assertEquals(2, response.getFailedCount());
+ Assert.assertFalse(response.isAllsuccessful());
+ Assert.assertNotNull(response.getFailures());
+ Assert.assertEquals(2, response.getFailures().size());
+ Assert.assertEquals(Long.valueOf(641L), response.getFailures().get(0).getExecutionId());
+ Assert.assertEquals(
+ "Unauthorized: Delete execution in project test",
+ response.getFailures().get(0).getMessage()
+ );
+ Assert.assertEquals(Long.valueOf(640L), response.getFailures().get(1).getExecutionId());
+ Assert.assertEquals(
+ "Unauthorized: Delete execution in project test",
+ response.getFailures().get(1).getMessage()
+ );
+ }
+ /**
+ * delete executions with success
+ */
+ @Test
+ @Betamax(tape = "delete_executions_success", mode = TapeMode.READ_ONLY)
+ public void deleteExecutionsSuccess() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_8, 12);
+ final DeleteExecutionsResponse response = client.deleteExecutions(
+ new HashSet() {{
+ add(640L);
+ add(641L);
+ }}
+ );
+ Assert.assertEquals(2, response.getRequestCount());
+ Assert.assertEquals(2, response.getSuccessCount());
+ Assert.assertEquals(0, response.getFailedCount());
+ Assert.assertTrue(response.isAllsuccessful());
+ Assert.assertNotNull(response.getFailures());
+ Assert.assertEquals(0, response.getFailures().size());
+ }
+ /**
+ * delete executions mixed success
+ */
+ @Test
+ @Betamax(tape = "delete_executions_mixed", mode = TapeMode.READ_ONLY)
+ public void deleteExecutionsMixed() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_8, 12);
+ final DeleteExecutionsResponse response = client.deleteExecutions(
+ new HashSet() {{
+ add(642L);
+ add(640L);
+ add(1640L);
+ }}
+ );
+ Assert.assertEquals(3, response.getRequestCount());
+ Assert.assertEquals(1, response.getSuccessCount());
+ Assert.assertEquals(2, response.getFailedCount());
+ Assert.assertFalse(response.isAllsuccessful());
+ Assert.assertNotNull(response.getFailures());
+ Assert.assertEquals(2, response.getFailures().size());
+ Assert.assertEquals(Long.valueOf(1640L), response.getFailures().get(0).getExecutionId());
+ Assert.assertEquals(
+ "Execution Not found: 1640",
+ response.getFailures().get(0).getMessage()
+ );
+ Assert.assertEquals(Long.valueOf(640L), response.getFailures().get(1).getExecutionId());
+ Assert.assertEquals(
+ "Execution Not found: 640",
+ response.getFailures().get(1).getMessage()
+ );
+ }
@Before
public void setUp() throws Exception {
// not that you can put whatever here, because we don't actually connect to the RunDeck instance
diff --git a/src/test/resources/betamax/tapes/delete_executions_mixed.yaml b/src/test/resources/betamax/tapes/delete_executions_mixed.yaml
new file mode 100644
index 0000000..c21657d
--- /dev/null
+++ b/src/test/resources/betamax/tapes/delete_executions_mixed.yaml
@@ -0,0 +1,26 @@
+!tape
+name: delete_executions_mixed
+interactions:
+- recorded: 2014-11-06T17:29:44.266Z
+ request:
+ method: POST
+ uri: http://rundeck.local:4440/api/12/executions/delete
+ headers:
+ Accept: text/xml
+ Content-Type: application/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ Transfer-Encoding: chunked
+ User-Agent: RunDeck API Java Client 12
+ X-RunDeck-Auth-Token: GG7uj1y6UGahOs7QlmeN2sIwz1Y2j7zI
+ response:
+ status: 200
+ headers:
+ Content-Type: application/xml;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=smlj6wcfe4yccemt6bptnmgy;Path=/
+ X-Rundeck-API-Version: '12'
+ X-Rundeck-API-XML-Response-Wrapper: 'false'
+ body: !!binary |-
+ PGRlbGV0ZUV4ZWN1dGlvbnMgcmVxdWVzdENvdW50PSczJyBhbGxzdWNjZXNzZnVsPSdmYWxzZSc+CiAgPHN1Y2Nlc3NmdWwgY291bnQ9JzEnIC8+CiAgPGZhaWxlZCBjb3VudD0nMic+CiAgICA8ZXhlY3V0aW9uIGlkPScxNjQwJyBtZXNzYWdlPSdFeGVjdXRpb24gTm90IGZvdW5kOiAxNjQwJyAvPgogICAgPGV4ZWN1dGlvbiBpZD0nNjQwJyBtZXNzYWdlPSdFeGVjdXRpb24gTm90IGZvdW5kOiA2NDAnIC8+CiAgPC9mYWlsZWQ+CjwvZGVsZXRlRXhlY3V0aW9ucz4=
diff --git a/src/test/resources/betamax/tapes/delete_executions_success.yaml b/src/test/resources/betamax/tapes/delete_executions_success.yaml
new file mode 100644
index 0000000..d412342
--- /dev/null
+++ b/src/test/resources/betamax/tapes/delete_executions_success.yaml
@@ -0,0 +1,26 @@
+!tape
+name: delete_executions_success
+interactions:
+- recorded: 2014-11-06T17:24:56.487Z
+ request:
+ method: POST
+ uri: http://rundeck.local:4440/api/12/executions/delete
+ headers:
+ Accept: text/xml
+ Content-Type: application/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ Transfer-Encoding: chunked
+ User-Agent: RunDeck API Java Client 12
+ X-RunDeck-Auth-Token: GG7uj1y6UGahOs7QlmeN2sIwz1Y2j7zI
+ response:
+ status: 200
+ headers:
+ Content-Type: application/xml;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=1xueq6cjfrsnxjn43hcfadqyk;Path=/
+ X-Rundeck-API-Version: '12'
+ X-Rundeck-API-XML-Response-Wrapper: 'false'
+ body: !!binary |-
+ PGRlbGV0ZUV4ZWN1dGlvbnMgcmVxdWVzdENvdW50PScyJyBhbGxzdWNjZXNzZnVsPSd0cnVlJz4KICA8c3VjY2Vzc2Z1bCBjb3VudD0nMicgLz4KPC9kZWxldGVFeGVjdXRpb25zPg==
diff --git a/src/test/resources/betamax/tapes/delete_executions_unauthorized.yaml b/src/test/resources/betamax/tapes/delete_executions_unauthorized.yaml
new file mode 100644
index 0000000..2f89d99
--- /dev/null
+++ b/src/test/resources/betamax/tapes/delete_executions_unauthorized.yaml
@@ -0,0 +1,26 @@
+!tape
+name: delete_executions_success
+interactions:
+- recorded: 2014-11-06T17:15:24.673Z
+ request:
+ method: POST
+ uri: http://rundeck.local:4440/api/12/executions/delete
+ headers:
+ Accept: text/xml
+ Content-Type: application/xml
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ Transfer-Encoding: chunked
+ User-Agent: RunDeck API Java Client 12
+ X-RunDeck-Auth-Token: GG7uj1y6UGahOs7QlmeN2sIwz1Y2j7zI
+ response:
+ status: 200
+ headers:
+ Content-Type: application/xml;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=1kzmot0r2scpjfxlcpfthh7tz;Path=/
+ X-Rundeck-API-Version: '12'
+ X-Rundeck-API-XML-Response-Wrapper: 'false'
+ body: !!binary |-
+ PGRlbGV0ZUV4ZWN1dGlvbnMgcmVxdWVzdENvdW50PScyJyBhbGxzdWNjZXNzZnVsPSdmYWxzZSc+CiAgPHN1Y2Nlc3NmdWwgY291bnQ9JzAnIC8+CiAgPGZhaWxlZCBjb3VudD0nMic+CiAgICA8ZXhlY3V0aW9uIGlkPSc2NDEnIG1lc3NhZ2U9J1VuYXV0aG9yaXplZDogRGVsZXRlIGV4ZWN1dGlvbiBpbiBwcm9qZWN0IHRlc3QnIC8+CiAgICA8ZXhlY3V0aW9uIGlkPSc2NDAnIG1lc3NhZ2U9J1VuYXV0aG9yaXplZDogRGVsZXRlIGV4ZWN1dGlvbiBpbiBwcm9qZWN0IHRlc3QnIC8+CiAgPC9mYWlsZWQ+CjwvZGVsZXRlRXhlY3V0aW9ucz4=
From b1c0a45da68c22d0ec8c1da134e2310039e9058f Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Thu, 6 Nov 2014 09:42:34 -0800
Subject: [PATCH 61/89] Fix javadoc, require nonzero size of executionIds
---
src/main/java/org/rundeck/api/RundeckClient.java | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/src/main/java/org/rundeck/api/RundeckClient.java b/src/main/java/org/rundeck/api/RundeckClient.java
index 93ced66..e68dd10 100644
--- a/src/main/java/org/rundeck/api/RundeckClient.java
+++ b/src/main/java/org/rundeck/api/RundeckClient.java
@@ -1649,17 +1649,20 @@ public class RundeckClient implements Serializable {
* Delete a set of executions, identified by the given IDs
*
* @param executionIds set of identifiers for the executions - mandatory
- * @return a {@link RundeckExecution} instance - won't be null
+ * @return a {@link DeleteExecutionsResponse} 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
+ * @throws IllegalArgumentException if the executionIds is null
*/
- public DeleteExecutionsResponse deleteExecutions(Set executionIds)
+ public DeleteExecutionsResponse deleteExecutions(final Set executionIds)
throws RundeckApiException, RundeckApiLoginException,
RundeckApiTokenException, IllegalArgumentException
{
AssertUtil.notNull(executionIds, "executionIds is mandatory to abort an execution !");
+ if (executionIds.size() < 1) {
+ throw new IllegalArgumentException("executionIds cannot be empty");
+ }
final ApiPathBuilder apiPath = new ApiPathBuilder("/executions/delete").xml(
new DeleteExecutionsGenerator(executionIds)
);
From e092ccdb1374df19882d1c4b892afbb0112cff3a Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Thu, 6 Nov 2014 09:48:55 -0800
Subject: [PATCH 62/89] Add delete single execution
---
.../java/org/rundeck/api/RundeckClient.java | 17 +++++++++
.../org/rundeck/api/RundeckClientTest.java | 36 +++++++++++++++++++
.../tapes/delete_execution_failure.yaml | 21 +++++++++++
.../tapes/delete_execution_success.yaml | 19 ++++++++++
4 files changed, 93 insertions(+)
create mode 100644 src/test/resources/betamax/tapes/delete_execution_failure.yaml
create mode 100644 src/test/resources/betamax/tapes/delete_execution_success.yaml
diff --git a/src/main/java/org/rundeck/api/RundeckClient.java b/src/main/java/org/rundeck/api/RundeckClient.java
index e68dd10..7811807 100644
--- a/src/main/java/org/rundeck/api/RundeckClient.java
+++ b/src/main/java/org/rundeck/api/RundeckClient.java
@@ -1672,6 +1672,23 @@ public class RundeckClient implements Serializable {
);
}
+ /**
+ * Delete a single execution, identified by the given ID
+ *
+ * @param executionId identifier for the execution - mandatory
+ * @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 void deleteExecution(final Long executionId)
+ throws RundeckApiException, RundeckApiLoginException,
+ RundeckApiTokenException, IllegalArgumentException
+ {
+ AssertUtil.notNull(executionId, "executionId is mandatory to abort an execution !");
+ new ApiCall(this).delete(new ApiPathBuilder("/execution/", executionId.toString()));
+ }
+
/*
* History
*/
diff --git a/src/test/java/org/rundeck/api/RundeckClientTest.java b/src/test/java/org/rundeck/api/RundeckClientTest.java
index 27fa3eb..e72aeb9 100644
--- a/src/test/java/org/rundeck/api/RundeckClientTest.java
+++ b/src/test/java/org/rundeck/api/RundeckClientTest.java
@@ -1572,6 +1572,42 @@ public class RundeckClientTest {
response.getFailures().get(1).getMessage()
);
}
+ /**
+ * delete single execution success
+ */
+ @Test
+ @Betamax(tape = "delete_execution_success", mode = TapeMode.READ_ONLY)
+ public void deleteExecutionSuccess() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_8, 12);
+ client.deleteExecution(643L);
+ }
+ /**
+ * delete single execution failure (does not exist)
+ */
+ @Test
+ @Betamax(tape = "delete_execution_failure", mode = TapeMode.READ_ONLY)
+ public void deleteExecutionFailure() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_8, 12);
+ try {
+ client.deleteExecution(640L);
+ Assert.fail();
+ } catch (RundeckApiException.RundeckApiHttpStatusException e) {
+ Assert.assertEquals(404, e.getStatusCode());
+ }
+ }
+ /**
+ * delete single execution null input
+ */
+ @Test
+ public void deleteExecutionNullInput() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_8, 12);
+ try {
+ client.deleteExecution(null);
+ Assert.fail();
+ } catch (IllegalArgumentException e) {
+
+ }
+ }
@Before
public void setUp() throws Exception {
// not that you can put whatever here, because we don't actually connect to the RunDeck instance
diff --git a/src/test/resources/betamax/tapes/delete_execution_failure.yaml b/src/test/resources/betamax/tapes/delete_execution_failure.yaml
new file mode 100644
index 0000000..fa26b88
--- /dev/null
+++ b/src/test/resources/betamax/tapes/delete_execution_failure.yaml
@@ -0,0 +1,21 @@
+!tape
+name: delete_execution_failure
+interactions:
+- recorded: 2014-11-06T17:45:47.952Z
+ request:
+ method: DELETE
+ uri: http://rundeck.local:4440/api/12/execution/640
+ headers:
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 12
+ X-RunDeck-Auth-Token: GG7uj1y6UGahOs7QlmeN2sIwz1Y2j7zI
+ response:
+ status: 404
+ headers:
+ Content-Type: text/xml;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=1eynpbisggwsy18ax352yya8k0;Path=/
+ X-Rundeck-API-Version: '12'
+ body: "\n \n Execution ID does not exist: 640 \n \n "
diff --git a/src/test/resources/betamax/tapes/delete_execution_success.yaml b/src/test/resources/betamax/tapes/delete_execution_success.yaml
new file mode 100644
index 0000000..3c2555a
--- /dev/null
+++ b/src/test/resources/betamax/tapes/delete_execution_success.yaml
@@ -0,0 +1,19 @@
+!tape
+name: delete_execution_success
+interactions:
+- recorded: 2014-11-06T17:45:47.749Z
+ request:
+ method: DELETE
+ uri: http://rundeck.local:4440/api/12/execution/643
+ headers:
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 12
+ X-RunDeck-Auth-Token: GG7uj1y6UGahOs7QlmeN2sIwz1Y2j7zI
+ response:
+ status: 204
+ headers:
+ Content-Type: text/html;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=1hlysemt7deir1j9r7l6ildg5x;Path=/
From a598c76d8eebeb8f5c91344209ab468ecd1c1bec Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Thu, 6 Nov 2014 10:05:35 -0800
Subject: [PATCH 63/89] Add delete all job executions endpoint
---
.../java/org/rundeck/api/RundeckClient.java | 31 ++++++++++++++--
.../org/rundeck/api/RundeckClientTest.java | 36 +++++++++++++++++++
.../delete_all_job_executions_success.yaml | 23 ++++++++++++
...elete_all_job_executions_unauthorized.yaml | 21 +++++++++++
4 files changed, 108 insertions(+), 3 deletions(-)
create mode 100644 src/test/resources/betamax/tapes/delete_all_job_executions_success.yaml
create mode 100644 src/test/resources/betamax/tapes/delete_all_job_executions_unauthorized.yaml
diff --git a/src/main/java/org/rundeck/api/RundeckClient.java b/src/main/java/org/rundeck/api/RundeckClient.java
index 7811807..5e3e1c0 100644
--- a/src/main/java/org/rundeck/api/RundeckClient.java
+++ b/src/main/java/org/rundeck/api/RundeckClient.java
@@ -1642,7 +1642,32 @@ public class RundeckClient implements Serializable {
if(null!=asUser) {
apiPath.param("asUser", asUser);
}
- return new ApiCall(this).get(apiPath, new AbortParser(rootXpath()+"/abort"));
+ return new ApiCall(this).get(apiPath, new AbortParser(rootXpath() + "/abort"));
+ }
+
+ /**
+ * Delete all executions for a job specified by a job ID
+ *
+ * @param jobId Identifier for the job
+ *
+ * @return a {@link DeleteExecutionsResponse} 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 executionIds is null
+ */
+ public DeleteExecutionsResponse deleteAllJobExecutions(final String jobId)
+ throws RundeckApiException, RundeckApiLoginException,
+ RundeckApiTokenException, IllegalArgumentException
+ {
+ AssertUtil.notNull(jobId, "jobId is mandatory to delete executions!");
+ return new ApiCall(this).delete(
+ new ApiPathBuilder("/job/",jobId,"/executions"),
+ new DeleteExecutionsResponseParser(rootXpath() + "/deleteExecutions")
+ );
}
/**
@@ -1659,7 +1684,7 @@ public class RundeckClient implements Serializable {
throws RundeckApiException, RundeckApiLoginException,
RundeckApiTokenException, IllegalArgumentException
{
- AssertUtil.notNull(executionIds, "executionIds is mandatory to abort an execution !");
+ AssertUtil.notNull(executionIds, "executionIds is mandatory to delete executions!");
if (executionIds.size() < 1) {
throw new IllegalArgumentException("executionIds cannot be empty");
}
@@ -1685,7 +1710,7 @@ public class RundeckClient implements Serializable {
throws RundeckApiException, RundeckApiLoginException,
RundeckApiTokenException, IllegalArgumentException
{
- AssertUtil.notNull(executionId, "executionId is mandatory to abort an execution !");
+ AssertUtil.notNull(executionId, "executionId is mandatory to delete an execution!");
new ApiCall(this).delete(new ApiPathBuilder("/execution/", executionId.toString()));
}
diff --git a/src/test/java/org/rundeck/api/RundeckClientTest.java b/src/test/java/org/rundeck/api/RundeckClientTest.java
index e72aeb9..b4f5ff4 100644
--- a/src/test/java/org/rundeck/api/RundeckClientTest.java
+++ b/src/test/java/org/rundeck/api/RundeckClientTest.java
@@ -1572,6 +1572,42 @@ public class RundeckClientTest {
response.getFailures().get(1).getMessage()
);
}
+ /**
+ * delete executions with failure
+ */
+ @Test
+ @Betamax(tape = "delete_all_job_executions_unauthorized", mode = TapeMode.READ_ONLY)
+ public void deleteAllJobExecutionsUnauthorized() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_8, 12);
+ try {
+ final DeleteExecutionsResponse response = client.deleteAllJobExecutions(
+ "764c1209-68ed-4185-8d43-a739364bf156"
+ );
+ Assert.fail();
+ } catch (RundeckApiException.RundeckApiTokenException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ *
+ * @throws Exception
+ */
+ @Test
+ @Betamax(tape = "delete_all_job_executions_success", mode = TapeMode.READ_ONLY)
+ public void deleteAllJobExecutionsSuccess() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_8, 12);
+ final DeleteExecutionsResponse response = client.deleteAllJobExecutions(
+ "764c1209-68ed-4185-8d43-a739364bf156"
+ );
+ Assert.assertEquals(2, response.getRequestCount());
+ Assert.assertEquals(2, response.getSuccessCount());
+ Assert.assertEquals(0, response.getFailedCount());
+ Assert.assertTrue(response.isAllsuccessful());
+ Assert.assertNotNull(response.getFailures());
+ Assert.assertEquals(0, response.getFailures().size());
+ }
+
/**
* delete single execution success
*/
diff --git a/src/test/resources/betamax/tapes/delete_all_job_executions_success.yaml b/src/test/resources/betamax/tapes/delete_all_job_executions_success.yaml
new file mode 100644
index 0000000..b68b5e2
--- /dev/null
+++ b/src/test/resources/betamax/tapes/delete_all_job_executions_success.yaml
@@ -0,0 +1,23 @@
+!tape
+name: delete_all_job_executions_success
+interactions:
+- recorded: 2014-11-06T18:03:44.789Z
+ request:
+ method: DELETE
+ uri: http://rundeck.local:4440/api/12/job/764c1209-68ed-4185-8d43-a739364bf156/executions
+ headers:
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 12
+ X-RunDeck-Auth-Token: GG7uj1y6UGahOs7QlmeN2sIwz1Y2j7zI
+ response:
+ status: 200
+ headers:
+ Content-Type: application/xml;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=cqqoff205qus10sz1v3t54rk7;Path=/
+ X-Rundeck-API-Version: '12'
+ X-Rundeck-API-XML-Response-Wrapper: 'false'
+ body: !!binary |-
+ PGRlbGV0ZUV4ZWN1dGlvbnMgcmVxdWVzdENvdW50PScyJyBhbGxzdWNjZXNzZnVsPSd0cnVlJz4KICA8c3VjY2Vzc2Z1bCBjb3VudD0nMicgLz4KPC9kZWxldGVFeGVjdXRpb25zPg==
diff --git a/src/test/resources/betamax/tapes/delete_all_job_executions_unauthorized.yaml b/src/test/resources/betamax/tapes/delete_all_job_executions_unauthorized.yaml
new file mode 100644
index 0000000..f4f898b
--- /dev/null
+++ b/src/test/resources/betamax/tapes/delete_all_job_executions_unauthorized.yaml
@@ -0,0 +1,21 @@
+!tape
+name: delete_all_job_executions_unauthorized
+interactions:
+- recorded: 2014-11-06T17:57:02.905Z
+ request:
+ method: DELETE
+ uri: http://rundeck.local:4440/api/12/job/764c1209-68ed-4185-8d43-a739364bf156/executions
+ headers:
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 12
+ X-RunDeck-Auth-Token: GG7uj1y6UGahOs7QlmeN2sIwz1Y2j7zI
+ response:
+ status: 403
+ headers:
+ Content-Type: text/xml;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=splzhkd5xunl1noidus2o7im3;Path=/
+ X-Rundeck-API-Version: '12'
+ body: "\n \n Not authorized for action \"Delete Execution\" for Project test \n \n "
From 40f5c5b891b8256d41b33562337b48035c97bdac Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Thu, 6 Nov 2014 10:06:07 -0800
Subject: [PATCH 64/89] Update API v12 todo
---
src/site/confluence/status.confluence | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/site/confluence/status.confluence b/src/site/confluence/status.confluence
index c161cf4..343131c 100644
--- a/src/site/confluence/status.confluence
+++ b/src/site/confluence/status.confluence
@@ -118,6 +118,6 @@ h2. Rundeck API version 12
[Documentation of the RunDeck API version 12|http://rundeck.org/2.2.0/api/index.html]
-* Bulk delete executions - TBD
-* Delete execution - TBD
-* Delete all executions for a job - TBD
+* Bulk delete executions - OK
+* Delete execution - OK
+* Delete all executions for a job - OK
From e2839d6244777115e608fc019d497d2b99f42266 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Thu, 6 Nov 2014 10:24:51 -0800
Subject: [PATCH 65/89] Expect 204 response for job delete for #14
---
.../java/org/rundeck/api/RundeckClient.java | 3 ++-
.../org/rundeck/api/RundeckClientTest.java | 26 +++++++++++++++++++
.../resources/betamax/tapes/delete_job.yaml | 19 ++++++++++++++
.../betamax/tapes/delete_job_not_found.yaml | 21 +++++++++++++++
4 files changed, 68 insertions(+), 1 deletion(-)
create mode 100644 src/test/resources/betamax/tapes/delete_job.yaml
create mode 100644 src/test/resources/betamax/tapes/delete_job_not_found.yaml
diff --git a/src/main/java/org/rundeck/api/RundeckClient.java b/src/main/java/org/rundeck/api/RundeckClient.java
index 8462dba..bc23457 100644
--- a/src/main/java/org/rundeck/api/RundeckClient.java
+++ b/src/main/java/org/rundeck/api/RundeckClient.java
@@ -1039,7 +1039,8 @@ public class RundeckClient implements Serializable {
public String deleteJob(String jobId) throws RundeckApiException, RundeckApiLoginException,
RundeckApiTokenException, IllegalArgumentException {
AssertUtil.notBlank(jobId, "jobId is mandatory to delete a job !");
- return new ApiCall(this).delete(new ApiPathBuilder("/job/", jobId), new StringParser(rootXpath()+"/success/message"));
+ new ApiCall(this).delete(new ApiPathBuilder("/job/", jobId));
+ return "Job " + jobId + " was deleted successfully";
}
/**
* Delete multiple jobs, identified by the given IDs
diff --git a/src/test/java/org/rundeck/api/RundeckClientTest.java b/src/test/java/org/rundeck/api/RundeckClientTest.java
index fb01b80..5dc6d59 100644
--- a/src/test/java/org/rundeck/api/RundeckClientTest.java
+++ b/src/test/java/org/rundeck/api/RundeckClientTest.java
@@ -1489,6 +1489,32 @@ public class RundeckClientTest {
Assert.assertEquals(404,e.getStatusCode());
}
}
+ /**
+ * delete job
+ */
+ @Test
+ @Betamax(tape = "delete_job", mode = TapeMode.READ_ONLY)
+ public void deleteJob() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_7, 11);
+ String result = client.deleteJob("api-test-job-run-scheduled");
+
+ Assert.assertEquals("Job api-test-job-run-scheduled was deleted successfully", result);
+ }
+ /**
+ * delete job (DNE)
+ */
+ @Test
+ @Betamax(tape = "delete_job_not_found", mode = TapeMode.READ_ONLY)
+ public void deleteJobNotFound() throws Exception {
+ final RundeckClient client = createClient(TEST_TOKEN_7, 11);
+ try {
+ String result = client.deleteJob("does-not-exist");
+ Assert.fail();
+ } catch (RundeckApiException.RundeckApiHttpStatusException e) {
+ Assert.assertEquals(404, e.getStatusCode());
+ }
+
+ }
@Before
public void setUp() throws Exception {
diff --git a/src/test/resources/betamax/tapes/delete_job.yaml b/src/test/resources/betamax/tapes/delete_job.yaml
new file mode 100644
index 0000000..29e33df
--- /dev/null
+++ b/src/test/resources/betamax/tapes/delete_job.yaml
@@ -0,0 +1,19 @@
+!tape
+name: delete_job
+interactions:
+- recorded: 2014-11-06T18:14:48.773Z
+ request:
+ method: DELETE
+ uri: http://rundeck.local:4440/api/11/job/api-test-job-run-scheduled
+ headers:
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
+ response:
+ status: 204
+ headers:
+ Content-Type: text/html;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=1hb33nx0a7qv21gyuoqes2pahg;Path=/
diff --git a/src/test/resources/betamax/tapes/delete_job_not_found.yaml b/src/test/resources/betamax/tapes/delete_job_not_found.yaml
new file mode 100644
index 0000000..f7540a6
--- /dev/null
+++ b/src/test/resources/betamax/tapes/delete_job_not_found.yaml
@@ -0,0 +1,21 @@
+!tape
+name: delete_job_not_found
+interactions:
+- recorded: 2014-11-06T18:21:13.147Z
+ request:
+ method: DELETE
+ uri: http://rundeck.local:4440/api/11/job/does-not-exist
+ headers:
+ Host: rundeck.local:4440
+ Proxy-Connection: Keep-Alive
+ User-Agent: RunDeck API Java Client 11
+ X-RunDeck-Auth-Token: 8Dp9op111ER6opsDRkddvE86K9sE499s
+ response:
+ status: 404
+ headers:
+ Content-Type: text/xml;charset=UTF-8
+ Expires: Thu, 01 Jan 1970 00:00:00 GMT
+ Server: Jetty(7.6.0.v20120127)
+ Set-Cookie: JSESSIONID=1sxop3bupsrqb1gupbru3vklba;Path=/
+ X-Rundeck-API-Version: '12'
+ body: "\n \n Job ID does not exist: does-not-exist \n \n "
From e73bb27058c3e7f55d8b7c06e19f3292fe0d95d1 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Thu, 6 Nov 2014 10:33:59 -0800
Subject: [PATCH 66/89] Release info
---
src/changes/changes.xml | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 825c4ca..6f25616 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -22,6 +22,11 @@
Vincent Behar
+
+
+ Issue #14: deleteJob fails
+
+
Project creation
Get Project configuration
From 7228205e57064ca124d546d6be7ec7df7aa0c710 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Thu, 6 Nov 2014 10:35:13 -0800
Subject: [PATCH 67/89] [maven-release-plugin] prepare release
rundeck-api-java-client-11.1
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 722956b..a7b9d1e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -27,7 +27,7 @@
org.rundeck
rundeck-api-java-client
- 11.1-SNAPSHOT
+ 11.1
jar
RunDeck API - Java Client
Java client for the RunDeck REST API
From d7928bc37e259f96d2d5dfb416c738f826facaf8 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Thu, 6 Nov 2014 10:35:17 -0800
Subject: [PATCH 68/89] [maven-release-plugin] prepare for next development
iteration
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index a7b9d1e..7d506cd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -27,7 +27,7 @@
org.rundeck
rundeck-api-java-client
- 11.1
+ 11.2-SNAPSHOT
jar
RunDeck API - Java Client
Java client for the RunDeck REST API
From 75231805ecd1981ef4797846a4c41e207b31a4e7 Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Fri, 7 Nov 2014 15:37:19 -0800
Subject: [PATCH 69/89] Test query parameter generation for date strings
---
.../api/ExecutionQueryParametersTest.java | 54 +++++++++++++++++++
1 file changed, 54 insertions(+)
create mode 100644 src/test/java/org/rundeck/api/ExecutionQueryParametersTest.java
diff --git a/src/test/java/org/rundeck/api/ExecutionQueryParametersTest.java b/src/test/java/org/rundeck/api/ExecutionQueryParametersTest.java
new file mode 100644
index 0000000..dad5254
--- /dev/null
+++ b/src/test/java/org/rundeck/api/ExecutionQueryParametersTest.java
@@ -0,0 +1,54 @@
+package org.rundeck.api;
+
+import junit.framework.Assert;
+import org.junit.Test;
+import org.rundeck.api.query.ExecutionQuery;
+
+import java.util.Arrays;
+import java.util.Date;
+
+/**
+ * ExecutionQueryParametersTest is ...
+ *
+ * @author Greg Schueler
+ * @since 2014-11-07
+ */
+public class ExecutionQueryParametersTest {
+
+ @Test
+ public void stringParameter() {
+ ExecutionQuery.Builder description = ExecutionQuery.builder().description("a description");
+ ExecutionQueryParameters executionQueryParameters = new ExecutionQueryParameters(
+ description.build()
+ );
+ ApiPathBuilder param = new ApiPathBuilder("").param(executionQueryParameters);
+ Assert.assertEquals("?descFilter=a+description", param.toString());
+ }
+ @Test
+ public void listParameter() {
+ ExecutionQuery.Builder description = ExecutionQuery.builder().excludeJobList(
+ Arrays.asList(
+ "a",
+ "b"
+ )
+ );
+ ExecutionQueryParameters executionQueryParameters = new ExecutionQueryParameters(
+ description.build()
+ );
+ ApiPathBuilder param = new ApiPathBuilder("").param(executionQueryParameters);
+ Assert.assertEquals("?excludeJobListFilter=a&excludeJobListFilter=b", param.toString());
+ }
+ @Test
+ public void dateParameter() {
+ ExecutionQuery.Builder description = ExecutionQuery.builder().end(
+ new Date(1347581178168L)
+ );
+ ExecutionQueryParameters executionQueryParameters = new ExecutionQueryParameters(
+ description.build()
+ );
+ ApiPathBuilder param = new ApiPathBuilder("").param(executionQueryParameters);
+ //nb: timezone should be GMT
+ //2012-09-14T00:06:18Z
+ Assert.assertEquals("?end=2012-09-14T00%3A06%3A18Z", param.toString());
+ }
+}
From 3219161dd34a23bcbfc7cb355e54e536e4b4544c Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Fri, 7 Nov 2014 15:42:22 -0800
Subject: [PATCH 70/89] Use GMT time zone for date formatter
---
src/main/java/org/rundeck/api/QueryParameterBuilder.java | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/main/java/org/rundeck/api/QueryParameterBuilder.java b/src/main/java/org/rundeck/api/QueryParameterBuilder.java
index 6fd0126..23db9bb 100644
--- a/src/main/java/org/rundeck/api/QueryParameterBuilder.java
+++ b/src/main/java/org/rundeck/api/QueryParameterBuilder.java
@@ -36,6 +36,9 @@ import java.util.*;
abstract class QueryParameterBuilder implements ApiPathBuilder.BuildsParameters {
public static final String W3C_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
static final SimpleDateFormat format = new SimpleDateFormat(W3C_DATE_FORMAT);
+ static {
+ format.setTimeZone(TimeZone.getTimeZone("GMT"));
+ }
/**
* Add a value to the builder for a given key
From 7bad157911feb120e57d8bf5d542ba34f8726efe Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Fri, 7 Nov 2014 15:42:37 -0800
Subject: [PATCH 71/89] Fix expected generated dates for executions test
---
src/test/resources/betamax/tapes/get_executions.yaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/test/resources/betamax/tapes/get_executions.yaml b/src/test/resources/betamax/tapes/get_executions.yaml
index 740a0c5..f87fb2d 100644
--- a/src/test/resources/betamax/tapes/get_executions.yaml
+++ b/src/test/resources/betamax/tapes/get_executions.yaml
@@ -38,7 +38,7 @@ interactions:
- recorded: 2012-09-14T22:04:13.342Z
request:
method: GET
- uri: http://rundeck.local:4440/api/5/executions?project=blah&begin=2012-09-13T17%3A06%3A18Z&max=2&offset=0
+ uri: http://rundeck.local:4440/api/5/executions?project=blah&begin=2012-09-14T00%3A06%3A18Z&max=2&offset=0
headers:
Accept: text/xml
Host: rundeck.local:4440
@@ -54,7 +54,7 @@ interactions:
- recorded: 2012-09-14T22:04:13.404Z
request:
method: GET
- uri: http://rundeck.local:4440/api/5/executions?project=blah&end=2012-09-13T17%3A06%3A18Z&max=2&offset=0
+ uri: http://rundeck.local:4440/api/5/executions?project=blah&end=2012-09-14T00%3A06%3A18Z&max=2&offset=0
headers:
Accept: text/xml
Host: rundeck.local:4440
From 18ec800264d9fcaefced41329c5be973f36cca1e Mon Sep 17 00:00:00 2001
From: Greg Schueler
Date: Fri, 7 Nov 2014 11:12:02 -0800
Subject: [PATCH 72/89] Test expected API v11 response
---
.../rundeck/api/parser/PagedResultParser.java | 11 +-
.../org/rundeck/api/RundeckClientTest.java | 126 ++++++
.../betamax/tapes/get_executions_v11.yaml | 419 ++++++++++++++++++
3 files changed, 554 insertions(+), 2 deletions(-)
create mode 100644 src/test/resources/betamax/tapes/get_executions_v11.yaml
diff --git a/src/main/java/org/rundeck/api/parser/PagedResultParser.java b/src/main/java/org/rundeck/api/parser/PagedResultParser.java
index 3eed01c..3389a87 100644
--- a/src/main/java/org/rundeck/api/parser/PagedResultParser.java
+++ b/src/main/java/org/rundeck/api/parser/PagedResultParser.java
@@ -26,6 +26,7 @@ package org.rundeck.api.parser;
import org.dom4j.Element;
import org.dom4j.Node;
+import org.rundeck.api.RundeckApiException;
import org.rundeck.api.util.PagedResults;
import java.util.*;
@@ -38,7 +39,7 @@ import java.util.*;
*/
public class PagedResultParser implements XmlNodeParser> {
ListParser itemParser;
- String xpath;
+ private String xpath;
/**
* Create a PagedResultParser
@@ -54,7 +55,9 @@ public class PagedResultParser implements XmlNodeParser> {
@Override
public PagedResults