Load an XML Document from the given RunDeck HttpResponse.
@@ -406,9 +403,6 @@ Constructor for class org.rundeck.api.parser.NodeParser(String) -
Constructor for class org.rundeck.api.parser.NodeParser
Test if the given String is blank (null, empty or only whitespace)
@@ -452,27 +446,18 @@ Method in class org.rundeck.api.parser.parseXmlNode(Node) -
Method in class org.rundeck.api.parser.ExecutionParser
Parse the given XML Node
@@ -485,9 +470,6 @@ Constructor for class org.rundeck.api.parser.ProjectParser(String) -
Constructor for class org.rundeck.api.parser.ProjectParser
Description: The codec package contains simple encoder and decoders for
various formats such as Base64 and Hexadecimal. In addition to these
widely used encoders and decoders, the codec package also maintains a
- collection of phonetic encoding utilities.
Description: Commons Lang, a package of Java utility classes for the
classes that are in java.lang's hierarchy, or are considered to be so
- standard as to justify existence in java.lang.
Project License: No project license is defined for this project.
xml-apis:xml-apis:jar:1.0.b2 (compile)
XML Commons External Components XML APIs
Description: xml-commons provides an Apache-hosted set of DOM, SAX, and
JAXP interfaces for use in other xml-based projects. Our hope is that we
can standardize on both a common version and packaging scheme for these
critical XML standards interfaces to make the lives of both our developers
and users easier. The External Components portion of xml-commons contains
interfaces that are defined by external standards organizations. For DOM,
that's the W3C; for SAX it's David Megginson and sax.sourceforge.net; for
- JAXP it's Sun.
Description: There is currently no description associated with this project.
Project License: No project license is defined for this project.
xerces:xercesImpl:jar:2.6.2 (compile)
Unnamed - xerces:xercesImpl:jar:2.6.2
Description: There is currently no description associated with this project.
Project License: No project license is defined for this project.
xalan:xalan:jar:2.6.0 (compile)
Unnamed - xalan:xalan:jar:2.6.0
Description: There is currently no description associated with this project.
Project License: No project license is defined for this project.
xml-apis:xml-apis:jar:1.0.b2 (compile)
XML Commons External Components XML APIs
Description: xml-commons provides an Apache-hosted set of DOM, SAX, and
JAXP interfaces for use in other xml-based projects. Our hope is that we
can standardize on both a common version and packaging scheme for these
critical XML standards interfaces to make the lives of both our developers
and users easier. The External Components portion of xml-commons contains
interfaces that are defined by external standards organizations. For DOM,
that's the W3C; for SAX it's David Megginson and sax.sourceforge.net; for
- JAXP it's Sun.
The Apache Software License, Version 2.0: Commons Codec, Commons Lang, Commons Logging, RunDeck API - Java Client, XML Commons External Components XML APIs
The Apache Software License, Version 2.0: Commons Codec, Commons Lang, Commons Logging, RunDeck API - Java Client, XML Commons External Components XML APIs
XML with no result should NOT throw an exception
@@ -141,9 +138,6 @@ Method in class org.rundeck.api.parser.NodeParserTest - Class in org.rundeck.api.parser
RundeckAbort
diff --git a/xref/org/rundeck/api/RundeckClient.html b/xref/org/rundeck/api/RundeckClient.html
index f68e9c9..f2a0d27 100644
--- a/xref/org/rundeck/api/RundeckClient.html
+++ b/xref/org/rundeck/api/RundeckClient.html
@@ -34,624 +34,624 @@
24import org.rundeck.api.RundeckApiException.RundeckApiLoginException;
25import org.rundeck.api.domain.RundeckAbort;
26import org.rundeck.api.domain.RundeckExecution;
-27import org.rundeck.api.domain.RundeckJob;
-28import org.rundeck.api.domain.RundeckNode;
-29import org.rundeck.api.domain.RundeckProject;
-30import org.rundeck.api.domain.RundeckExecution.ExecutionStatus;
+27import org.rundeck.api.domain.RundeckExecution.ExecutionStatus;
+28import org.rundeck.api.domain.RundeckJob;
+29import org.rundeck.api.domain.RundeckNode;
+30import org.rundeck.api.domain.RundeckProject;
31import org.rundeck.api.parser.AbortParser;
32import org.rundeck.api.parser.ExecutionParser;
-33import org.rundeck.api.parser.ExecutionsParser;
-34import org.rundeck.api.parser.JobParser;
-35import org.rundeck.api.parser.JobsParser;
-36import org.rundeck.api.parser.NodeParser;
-37import org.rundeck.api.parser.NodesParser;
-38import org.rundeck.api.parser.ProjectParser;
-39import org.rundeck.api.parser.ProjectsParser;
-40import org.rundeck.api.util.AssertUtil;
-41import org.rundeck.api.util.ParametersUtil;
-42
-43/**
-44 * Main entry point to talk to a RunDeck instance.<br>
-45 * Usage : <br>
-46 * <code>
-47 * <pre>
-48 * RundeckClient rundeck = new RundeckClient("http://localhost:4440", "admin", "admin");
-49 * List<RundeckJob> jobs = rundeck.getJobs();
-50 *
-51 * RundeckJob job = rundeck.findJob("my-project", "main-group/sub-group", "job-name");
-52 * RundeckExecution execution = rundeck.triggerJob(job.getId(),
-53 * new OptionsBuilder().addOption("version", "1.2.0").toProperties());
-54 *
-55 * List<RundeckExecution> runningExecutions = rundeck.getRunningExecutions("my-project");
-56 * </pre>
-57 * </code>
-58 *
-59 * @author Vincent Behar
-60 */
-61publicclassRundeckClientimplements Serializable {
-62
-63privatestaticfinallong serialVersionUID = 1L;
-64
-65publicstaticfinaltransientint API_VERSION = 1;
-66
-67publicstaticfinaltransient String API_ENDPOINT = "/api/" + API_VERSION;
-68
-69privatefinal String url;
-70
-71privatefinal String login;
-72
-73privatefinal String password;
-74
-75/**
-76 * Instantiate a new {@link RundeckClient} for the RunDeck instance at the given url
-77 *
-78 * @param url of the RunDeck instance ("http://localhost:4440", "http://rundeck.your-compagny.com/", etc)
-79 * @param login
-80 * @param password
-81 * @throws IllegalArgumentException if the url, login or password is blank (null, empty or whitespace)
-82 */
-83publicRundeckClient(String url, String login, String password) throws IllegalArgumentException {
-84super();
-85this.url = url;
-86this.login = login;
-87this.password = password;
-88 AssertUtil.notBlank(url, "The RunDeck URL is mandatory !");
-89 AssertUtil.notBlank(login, "The RunDeck login is mandatory !");
-90 AssertUtil.notBlank(password, "The RunDeck password is mandatory !");
-91 }
-92
-93/**
-94 * Try to "ping" the RunDeck instance to see if it is alive
-95 *
-96 * @throws RundeckApiException if the ping fails
-97 */
-98publicvoid ping() throws RundeckApiException {
-99newApiCall(this).ping();
-100 }
-101
-102/**
-103 * Test your credentials (login/password) on the RunDeck instance
-104 *
-105 * @throws RundeckApiLoginException if the login fails
-106 */
-107publicvoid testCredentials() throws RundeckApiLoginException {
-108newApiCall(this).testCredentials();
-109 }
-110
-111/*
-112 * Projects
-113 */
-114
-115/**
-116 * List all projects
-117 *
-118 * @return a {@link List} of {@link RundeckProject} : might be empty, but won't be null
-119 * @throws RundeckApiException in case of error when calling the API
-120 * @throws RundeckApiLoginException if the login failed
-121 */
-122public List<RundeckProject> getProjects() throws RundeckApiException, RundeckApiLoginException {
-123returnnewApiCall(this).get(newApiPathBuilder("/projects"), newProjectsParser("result/projects/project"));
-124 }
-125
-126/**
-127 * Get the definition of a single project, identified by the given name
-128 *
-129 * @param projectName name of the project - mandatory
-130 * @return a {@link RundeckProject} instance - won't be null
-131 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
-132 * @throws RundeckApiLoginException if the login failed
-133 * @throws IllegalArgumentException if the projectName is blank (null, empty or whitespace)
-134 */
-135publicRundeckProject getProject(String projectName) throws RundeckApiException, RundeckApiLoginException,
-136 IllegalArgumentException {
-137 AssertUtil.notBlank(projectName, "projectName is mandatory to get the details of a project !");
-138returnnewApiCall(this).get(newApiPathBuilder("/project/", projectName),
-139newProjectParser("result/projects/project"));
-140 }
-141
-142/*
-143 * Jobs
-144 */
-145
-146/**
-147 * List all jobs (for all projects)
-148 *
-149 * @return a {@link List} of {@link RundeckJob} : might be empty, but won't be null
-150 * @throws RundeckApiException in case of error when calling the API
-151 * @throws RundeckApiLoginException if the login failed
-152 */
-153public List<RundeckJob> getJobs() throws RundeckApiException, RundeckApiLoginException {
-154 List<RundeckJob> jobs = new ArrayList<RundeckJob>();
-155for (RundeckProject project : getProjects()) {
-156 jobs.addAll(getJobs(project.getName()));
-157 }
-158return jobs;
-159 }
-160
-161/**
-162 * List all jobs that belongs to the given project
-163 *
-164 * @param project name of the project - mandatory
-165 * @return a {@link List} of {@link RundeckJob} : might be empty, but won't be null
-166 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
-167 * @throws RundeckApiLoginException if the login failed
-168 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
-169 * @see #getJobs(String, String, String, String...)
-170 */
-171public List<RundeckJob> getJobs(String project) throws RundeckApiException, RundeckApiLoginException,
-172 IllegalArgumentException {
-173return getJobs(project, null, null, new String[0]);
-174 }
-175
-176/**
-177 * List the jobs that belongs to the given project, and matches the given criteria (jobFilter, groupPath and jobIds)
-178 *
-179 * @param project name of the project - mandatory
-180 * @param jobFilter a filter for the job Name - optional
-181 * @param groupPath a group or partial group path to include all jobs within that group path - optional
-182 * @param jobIds a list of Job IDs to include - optional
-183 * @return a {@link List} of {@link RundeckJob} : might be empty, but won't be null
-184 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
-185 * @throws RundeckApiLoginException if the login failed
-186 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
-187 * @see #getJobs(String)
-188 */
-189public List<RundeckJob> getJobs(String project, String jobFilter, String groupPath, String... jobIds)
-190throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
-191 AssertUtil.notBlank(project, "project is mandatory to get all jobs !");
-192returnnewApiCall(this).get(newApiPathBuilder("/jobs").param("project", project)
-193 .param("jobFilter", jobFilter)
-194 .param("groupPath", groupPath)
-195 .param("idlist", StringUtils.join(jobIds, ",")),
-196newJobsParser("result/jobs/job"));
-197 }
-198
-199/**
-200 * Find a job, identified by its project, group and name. Note that the groupPath is optional, as a job does not
-201 * need to belong to a group (either pass null, or an empty string).
-202 *
-203 * @param project name of the project - mandatory
-204 * @param groupPath group to which the job belongs (if it belongs to a group) - optional
-205 * @param name of the job to find - mandatory
-206 * @return a {@link RundeckJob} instance - null if not found
-207 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
-208 * @throws RundeckApiLoginException if the login failed
-209 * @throws IllegalArgumentException if the project or the name is blank (null, empty or whitespace)
-210 */
-211publicRundeckJob findJob(String project, String groupPath, String name) throws RundeckApiException,
-212 RundeckApiLoginException, IllegalArgumentException {
-213 AssertUtil.notBlank(project, "project is mandatory to find a job !");
-214 AssertUtil.notBlank(name, "job name is mandatory to find a job !");
-215 List<RundeckJob> jobs = getJobs(project, name, groupPath, new String[0]);
-216return jobs.isEmpty() ? null : jobs.get(0);
-217 }
-218
-219/**
-220 * Get the definition of a single job, identified by the given ID
-221 *
-222 * @param jobId identifier of the job - mandatory
-223 * @return a {@link RundeckJob} instance - won't be null
-224 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
-225 * @throws RundeckApiLoginException if the login failed
-226 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
-227 */
-228publicRundeckJob getJob(String jobId) throws RundeckApiException, RundeckApiLoginException,
-229 IllegalArgumentException {
-230 AssertUtil.notBlank(jobId, "jobId is mandatory to get the details of a job !");
-231returnnewApiCall(this).get(newApiPathBuilder("/job/", jobId), newJobParser("joblist/job"));
-232 }
-233
-234/**
-235 * Trigger the execution of a RunDeck job (identified by the given ID), and return immediately (without waiting the
-236 * end of the job execution)
-237 *
-238 * @param jobId identifier of the job - mandatory
-239 * @return a {@link RundeckExecution} instance for the newly created (and running) execution - won't be null
-240 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
-241 * @throws RundeckApiLoginException if the login failed
-242 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
-243 * @see #triggerJob(String, Properties, Properties)
-244 * @see #runJob(String)
-245 */
-246publicRundeckExecution triggerJob(String jobId) throws RundeckApiException, RundeckApiLoginException,
-247 IllegalArgumentException {
-248return triggerJob(jobId, null);
-249 }
-250
-251/**
-252 * Trigger the execution of a RunDeck job (identified by the given ID), and return immediately (without waiting the
-253 * end of the job execution)
-254 *
-255 * @param jobId identifier of the job - mandatory
-256 * @param options of the job - optional. See {@link OptionsBuilder}.
-257 * @return a {@link RundeckExecution} instance for the newly created (and running) execution - won't be null
-258 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
-259 * @throws RundeckApiLoginException if the login failed
-260 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
-261 * @see #triggerJob(String, Properties, Properties)
-262 * @see #runJob(String, Properties)
-263 */
-264publicRundeckExecution triggerJob(String jobId, Properties options) throws RundeckApiException,
-265 RundeckApiLoginException, IllegalArgumentException {
-266return triggerJob(jobId, options, null);
-267 }
-268
-269/**
-270 * Trigger the execution of a RunDeck job (identified by the given ID), and return immediately (without waiting the
-271 * end of the job execution)
-272 *
-273 * @param jobId identifier of the job - mandatory
-274 * @param options of the job - optional. See {@link OptionsBuilder}.
-275 * @param nodeFilters for overriding the nodes on which the job will be executed - optional. See
-276 * {@link NodeFiltersBuilder}
-277 * @return a {@link RundeckExecution} instance for the newly created (and running) execution - won't be null
-278 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
-279 * @throws RundeckApiLoginException if the login failed
-280 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
-281 * @see #triggerJob(String)
-282 * @see #runJob(String, Properties, Properties)
-283 */
-284publicRundeckExecution triggerJob(String jobId, Properties options, Properties nodeFilters)
-285throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
-286 AssertUtil.notBlank(jobId, "jobId is mandatory to trigger a job !");
-287returnnewApiCall(this).get(newApiPathBuilder("/job/", jobId, "/run").param("argString",
-288 ParametersUtil.generateArgString(options))
-289 .nodeFilters(nodeFilters),
-290newExecutionParser("result/executions/execution"));
-291 }
-292
-293/**
-294 * Run a RunDeck job (identified by the given ID), and wait until its execution is finished (or aborted) to return.
-295 * We will poll the RunDeck server at regular interval (every 5 seconds) to know if the execution is finished (or
-296 * aborted) or is still running.
-297 *
-298 * @param jobId identifier of the job - mandatory
-299 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
-300 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
-301 * @throws RundeckApiLoginException if the login failed
-302 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
-303 * @see #triggerJob(String)
-304 * @see #runJob(String, Properties, Properties, long, TimeUnit)
-305 */
-306publicRundeckExecution runJob(String jobId) throws RundeckApiException, RundeckApiLoginException,
-307 IllegalArgumentException {
-308return runJob(jobId, null);
-309 }
-310
-311/**
-312 * Run a RunDeck job (identified by the given ID), and wait until its execution is finished (or aborted) to return.
-313 * We will poll the RunDeck server at regular interval (every 5 seconds) to know if the execution is finished (or
-314 * aborted) or is still running.
-315 *
-316 * @param jobId identifier of the job - mandatory
-317 * @param options of the job - optional. See {@link OptionsBuilder}.
-318 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
-319 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
-320 * @throws RundeckApiLoginException if the login failed
-321 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
-322 * @see #triggerJob(String, Properties)
-323 * @see #runJob(String, Properties, Properties, long, TimeUnit)
-324 */
-325publicRundeckExecution runJob(String jobId, Properties options) throws RundeckApiException,
-326 RundeckApiLoginException, IllegalArgumentException {
-327return runJob(jobId, options, null);
-328 }
-329
-330/**
-331 * Run a RunDeck job (identified by the given ID), and wait until its execution is finished (or aborted) to return.
-332 * We will poll the RunDeck server at regular interval (every 5 seconds) to know if the execution is finished (or
-333 * aborted) or is still running.
-334 *
-335 * @param jobId identifier of the job - mandatory
-336 * @param options of the job - optional. See {@link OptionsBuilder}.
-337 * @param nodeFilters for overriding the nodes on which the job will be executed - optional. See
-338 * {@link NodeFiltersBuilder}
-339 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
-340 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
-341 * @throws RundeckApiLoginException if the login failed
-342 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
-343 * @see #triggerJob(String, Properties, Properties)
-344 * @see #runJob(String, Properties, Properties, long, TimeUnit)
-345 */
-346publicRundeckExecution runJob(String jobId, Properties options, Properties nodeFilters)
-347throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
-348return runJob(jobId, options, nodeFilters, 5, TimeUnit.SECONDS);
-349 }
-350
-351/**
-352 * Run a RunDeck job (identified by the given ID), and wait until its execution is finished (or aborted) to return.
-353 * We will poll the RunDeck server at regular interval (configured by the poolingInterval/poolingUnit couple) to
-354 * know if the execution is finished (or aborted) or is still running.
-355 *
-356 * @param jobId identifier of the job - mandatory
-357 * @param options of the job - optional. See {@link OptionsBuilder}.
-358 * @param poolingInterval for checking the status of the execution. Must be > 0.
-359 * @param poolingUnit unit (seconds, milli-seconds, ...) of the interval. Default to seconds.
-360 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
-361 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
-362 * @throws RundeckApiLoginException if the login failed
-363 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
-364 * @see #triggerJob(String, Properties)
-365 * @see #runJob(String, Properties, Properties, long, TimeUnit)
-366 */
-367publicRundeckExecution runJob(String jobId, Properties options, long poolingInterval, TimeUnit poolingUnit)
-368throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
-369return runJob(jobId, options, null, poolingInterval, poolingUnit);
-370 }
-371
-372/**
-373 * Run a RunDeck job (identified by the given ID), and wait until its execution is finished (or aborted) to return.
-374 * We will poll the RunDeck server at regular interval (configured by the poolingInterval/poolingUnit couple) to
-375 * know if the execution is finished (or aborted) or is still running.
-376 *
-377 * @param jobId identifier of the job - mandatory
-378 * @param options of the job - optional. See {@link OptionsBuilder}.
-379 * @param nodeFilters for overriding the nodes on which the job will be executed - optional. See
-380 * {@link NodeFiltersBuilder}
-381 * @param poolingInterval for checking the status of the execution. Must be > 0.
-382 * @param poolingUnit unit (seconds, milli-seconds, ...) of the interval. Default to seconds.
-383 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
-384 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
-385 * @throws RundeckApiLoginException if the login failed
-386 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
-387 * @see #triggerJob(String, Properties)
-388 * @see #runJob(String, Properties, Properties, long, TimeUnit)
-389 */
-390publicRundeckExecution runJob(String jobId, Properties options, Properties nodeFilters, long poolingInterval,
-391 TimeUnit poolingUnit) throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
-392if (poolingInterval <= 0) {
-393 poolingInterval = 5;
-394 poolingUnit = TimeUnit.SECONDS;
-395 }
-396if (poolingUnit == null) {
-397 poolingUnit = TimeUnit.SECONDS;
-398 }
-399
-400RundeckExecution execution = triggerJob(jobId, options, nodeFilters);
-401while (ExecutionStatus.RUNNING.equals(execution.getStatus())) {
-402try {
-403 Thread.sleep(poolingUnit.toMillis(poolingInterval));
-404 } catch (InterruptedException e) {
-405break;
-406 }
-407 execution = getExecution(execution.getId());
-408 }
-409return execution;
-410 }
-411
-412/*
-413 * Ad-hoc commands
-414 */
-415
-416/**
-417 * Trigger the execution of an ad-hoc command, and return immediately (without waiting the end of the execution).
-418 * The command will not be dispatched to nodes, but be executed on the RunDeck server.
-419 *
-420 * @param project name of the project - mandatory
-421 * @param command to be executed - mandatory
-422 * @return a {@link RundeckExecution} instance for the newly created (and running) execution - won't be null
-423 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
-424 * @throws RundeckApiLoginException if the login failed
-425 * @throws IllegalArgumentException if the project or command is blank (null, empty or whitespace)
-426 * @see #triggerAdhocCommand(String, String, Properties)
-427 * @see #runAdhocCommand(String, String)
-428 */
-429publicRundeckExecution triggerAdhocCommand(String project, String command) throws RundeckApiException,
-430 RundeckApiLoginException, IllegalArgumentException {
-431return triggerAdhocCommand(project, command, null);
-432 }
-433
-434/**
-435 * Trigger the execution of an ad-hoc command, and return immediately (without waiting the end of the execution).
-436 * The command will be dispatched to nodes, accordingly to the nodeFilters parameter.
-437 *
-438 * @param project name of the project - mandatory
-439 * @param command to be executed - mandatory
-440 * @param nodeFilters for selecting nodes on which the command will be executed. See {@link NodeFiltersBuilder}
-441 * @return a {@link RundeckExecution} instance for the newly created (and running) execution - won't be null
-442 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
-443 * @throws RundeckApiLoginException if the login failed
-444 * @throws IllegalArgumentException if the project or command is blank (null, empty or whitespace)
-445 * @see #triggerAdhocCommand(String, String)
-446 * @see #runAdhocCommand(String, String, Properties)
-447 */
-448publicRundeckExecution triggerAdhocCommand(String project, String command, Properties nodeFilters)
-449throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
-450 AssertUtil.notBlank(project, "project is mandatory to trigger an ad-hoc command !");
-451 AssertUtil.notBlank(command, "command is mandatory to trigger an ad-hoc command !");
-452RundeckExecution execution = newApiCall(this).get(newApiPathBuilder("/run/command").param("project", project)
-453 .param("exec", command)
-454 .nodeFilters(nodeFilters),
-455newExecutionParser("result/execution"));
-456// the first call just returns the ID of the execution, so we need another call to get a "real" execution
-457return getExecution(execution.getId());
-458 }
-459
-460/**
-461 * Run an ad-hoc command, and wait until its execution is finished (or aborted) to return. We will poll the RunDeck
-462 * server at regular interval (every 5 seconds) to know if the execution is finished (or aborted) or is still
-463 * running. The command will not be dispatched to nodes, but be executed on the RunDeck server.
-464 *
-465 * @param project name of the project - mandatory
-466 * @param command to be executed - mandatory
-467 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
-468 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
-469 * @throws RundeckApiLoginException if the login failed
-470 * @throws IllegalArgumentException if the project or command is blank (null, empty or whitespace)
-471 * @see #runAdhocCommand(String, String, Properties, long, TimeUnit)
-472 * @see #triggerAdhocCommand(String, String)
-473 */
-474publicRundeckExecution runAdhocCommand(String project, String command) throws RundeckApiException,
-475 RundeckApiLoginException, IllegalArgumentException {
-476return runAdhocCommand(project, command, null);
-477 }
-478
-479/**
-480 * Run an ad-hoc command, and wait until its execution is finished (or aborted) to return. We will poll the RunDeck
-481 * server at regular interval (configured by the poolingInterval/poolingUnit couple) to know if the execution is
-482 * finished (or aborted) or is still running. The command will not be dispatched to nodes, but be executed on the
-483 * RunDeck server.
-484 *
-485 * @param project name of the project - mandatory
-486 * @param command to be executed - mandatory
-487 * @param poolingInterval for checking the status of the execution. Must be > 0.
-488 * @param poolingUnit unit (seconds, milli-seconds, ...) of the interval. Default to seconds.
-489 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
-490 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
-491 * @throws RundeckApiLoginException if the login failed
-492 * @throws IllegalArgumentException if the project or command is blank (null, empty or whitespace)
-493 * @see #runAdhocCommand(String, String, Properties, long, TimeUnit)
-494 * @see #triggerAdhocCommand(String, String)
-495 */
-496publicRundeckExecution runAdhocCommand(String project, String command, long poolingInterval, TimeUnit poolingUnit)
-497throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
-498return runAdhocCommand(project, command, null, poolingInterval, poolingUnit);
-499 }
-500
-501/**
-502 * Run an ad-hoc command, and wait until its execution is finished (or aborted) to return. We will poll the RunDeck
-503 * server at regular interval (every 5 seconds) to know if the execution is finished (or aborted) or is still
-504 * running. The command will be dispatched to nodes, accordingly to the nodeFilters parameter.
-505 *
-506 * @param project name of the project - mandatory
-507 * @param command to be executed - mandatory
-508 * @param nodeFilters for selecting nodes on which the command will be executed. See {@link NodeFiltersBuilder}
-509 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
-510 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
-511 * @throws RundeckApiLoginException if the login failed
-512 * @throws IllegalArgumentException if the project or command is blank (null, empty or whitespace)
-513 * @see #runAdhocCommand(String, String, Properties, long, TimeUnit)
-514 * @see #triggerAdhocCommand(String, String, Properties)
-515 */
-516publicRundeckExecution runAdhocCommand(String project, String command, Properties nodeFilters)
-517throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
-518return runAdhocCommand(project, command, nodeFilters, 5, TimeUnit.SECONDS);
-519 }
-520
-521/**
-522 * Run an ad-hoc command, and wait until its execution is finished (or aborted) to return. We will poll the RunDeck
-523 * server at regular interval (configured by the poolingInterval/poolingUnit couple) to know if the execution is
-524 * finished (or aborted) or is still running. The command will be dispatched to nodes, accordingly to the
-525 * nodeFilters parameter.
-526 *
-527 * @param project name of the project - mandatory
-528 * @param command to be executed - mandatory
-529 * @param nodeFilters for selecting nodes on which the command will be executed. See {@link NodeFiltersBuilder}
-530 * @param poolingInterval for checking the status of the execution. Must be > 0.
-531 * @param poolingUnit unit (seconds, milli-seconds, ...) of the interval. Default to seconds.
-532 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
-533 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
-534 * @throws RundeckApiLoginException if the login failed
-535 * @throws IllegalArgumentException if the project or command is blank (null, empty or whitespace)
-536 * @see #triggerAdhocCommand(String, String, Properties)
-537 */
-538publicRundeckExecution runAdhocCommand(String project, String command, Properties nodeFilters,
-539long poolingInterval, TimeUnit poolingUnit) throws RundeckApiException, RundeckApiLoginException,
-540 IllegalArgumentException {
-541if (poolingInterval <= 0) {
-542 poolingInterval = 5;
-543 poolingUnit = TimeUnit.SECONDS;
-544 }
-545if (poolingUnit == null) {
-546 poolingUnit = TimeUnit.SECONDS;
-547 }
-548
-549RundeckExecution execution = triggerAdhocCommand(project, command, nodeFilters);
-550while (ExecutionStatus.RUNNING.equals(execution.getStatus())) {
-551try {
-552 Thread.sleep(poolingUnit.toMillis(poolingInterval));
-553 } catch (InterruptedException e) {
-554break;
-555 }
-556 execution = getExecution(execution.getId());
-557 }
-558return execution;
-559 }
-560
-561/*
-562 * Executions
-563 */
-564
-565/**
-566 * Get all running executions (for all projects)
-567 *
-568 * @return a {@link List} of {@link RundeckExecution} : might be empty, but won't be null
-569 * @throws RundeckApiException in case of error when calling the API
-570 * @throws RundeckApiLoginException if the login failed
-571 */
-572public List<RundeckExecution> getRunningExecutions() throws RundeckApiException, RundeckApiLoginException {
-573 List<RundeckExecution> executions = new ArrayList<RundeckExecution>();
-574for (RundeckProject project : getProjects()) {
-575 executions.addAll(getRunningExecutions(project.getName()));
-576 }
-577return executions;
-578 }
-579
-580/**
-581 * Get the running executions for the given project
-582 *
-583 * @param project name of the project - mandatory
-584 * @return a {@link List} of {@link RundeckExecution} : might be empty, but won't be null
-585 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
-586 * @throws RundeckApiLoginException if the login failed
-587 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
-588 */
-589public List<RundeckExecution> getRunningExecutions(String project) throws RundeckApiException,
-590 RundeckApiLoginException, IllegalArgumentException {
-591 AssertUtil.notBlank(project, "project is mandatory get all running executions !");
-592returnnewApiCall(this).get(newApiPathBuilder("/executions/running").param("project", project),
-593newExecutionsParser("result/executions/execution"));
-594 }
-595
-596/**
-597 * Get the executions of the given job
-598 *
-599 * @param jobId identifier of the job - mandatory
-600 * @return a {@link List} of {@link RundeckExecution} : might be empty, but won't be null
-601 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
-602 * @throws RundeckApiLoginException if the login failed
-603 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
-604 */
-605public List<RundeckExecution> getJobExecutions(String jobId) throws RundeckApiException, RundeckApiLoginException,
-606 IllegalArgumentException {
-607return getJobExecutions(jobId, null);
-608 }
-609
-610/**
-611 * Get the executions of the given job
-612 *
-613 * @param jobId identifier of the job - mandatory
-614 * @param status of the executions - optional (null for all)
-615 * @return a {@link List} of {@link RundeckExecution} : might be empty, but won't be null
-616 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
-617 * @throws RundeckApiLoginException if the login failed
-618 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
-619 */
-620public List<RundeckExecution> getJobExecutions(String jobId, ExecutionStatus status) throws RundeckApiException,
-621 RundeckApiLoginException, IllegalArgumentException {
-622return getJobExecutions(jobId, status, null, null);
-623 }
-624
-625/**
-626 * Get the executions of the given job
-627 *
-628 * @param jobId identifier of the job - mandatory
-629 * @param status of the executions - optional (null for all)
-630 * @param max number of results to return - optional (null for all)
-631 * @param offset the 0-indexed offset for the first result to return - optional
-632 * @return a {@link List} of {@link RundeckExecution} : might be empty, but won't be null
-633 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
-634 * @throws RundeckApiLoginException if the login failed
-635 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
-636 */
-637public List<RundeckExecution> getJobExecutions(String jobId, ExecutionStatus status, Long max, Long offset)
-638throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
-639 AssertUtil.notBlank(jobId, "jobId is mandatory to get the executions of a job !");
-640returnnewApiCall(this).get(newApiPathBuilder("/job/", jobId, "/executions").param("status",
-641 status != null ? StringUtils.lowerCase(status.toString()) : null)
-642 .param("max", max)
-643 .param("offset", offset),
-644newExecutionsParser("result/executions/execution"));
+33import org.rundeck.api.parser.JobParser;
+34import org.rundeck.api.parser.ListParser;
+35import org.rundeck.api.parser.NodeParser;
+36import org.rundeck.api.parser.ProjectParser;
+37import org.rundeck.api.util.AssertUtil;
+38import org.rundeck.api.util.ParametersUtil;
+39
+40/**
+41 * Main entry point to talk to a RunDeck instance.<br>
+42 * Usage : <br>
+43 * <code>
+44 * <pre>
+45 * RundeckClient rundeck = new RundeckClient("http://localhost:4440", "admin", "admin");
+46 * List<RundeckJob> jobs = rundeck.getJobs();
+47 *
+48 * RundeckJob job = rundeck.findJob("my-project", "main-group/sub-group", "job-name");
+49 * RundeckExecution execution = rundeck.triggerJob(job.getId(),
+50 * new OptionsBuilder().addOption("version", "1.2.0").toProperties());
+51 *
+52 * List<RundeckExecution> runningExecutions = rundeck.getRunningExecutions("my-project");
+53 * </pre>
+54 * </code>
+55 *
+56 * @author Vincent Behar
+57 */
+58publicclassRundeckClientimplements Serializable {
+59
+60privatestaticfinallong serialVersionUID = 1L;
+61
+62publicstaticfinaltransientint API_VERSION = 1;
+63
+64publicstaticfinaltransient String API_ENDPOINT = "/api/" + API_VERSION;
+65
+66privatefinal String url;
+67
+68privatefinal String login;
+69
+70privatefinal String password;
+71
+72/**
+73 * Instantiate a new {@link RundeckClient} for the RunDeck instance at the given url
+74 *
+75 * @param url of the RunDeck instance ("http://localhost:4440", "http://rundeck.your-compagny.com/", etc)
+76 * @param login
+77 * @param password
+78 * @throws IllegalArgumentException if the url, login or password is blank (null, empty or whitespace)
+79 */
+80publicRundeckClient(String url, String login, String password) throws IllegalArgumentException {
+81super();
+82this.url = url;
+83this.login = login;
+84this.password = password;
+85 AssertUtil.notBlank(url, "The RunDeck URL is mandatory !");
+86 AssertUtil.notBlank(login, "The RunDeck login is mandatory !");
+87 AssertUtil.notBlank(password, "The RunDeck password is mandatory !");
+88 }
+89
+90/**
+91 * Try to "ping" the RunDeck instance to see if it is alive
+92 *
+93 * @throws RundeckApiException if the ping fails
+94 */
+95publicvoid ping() throws RundeckApiException {
+96newApiCall(this).ping();
+97 }
+98
+99/**
+100 * Test your credentials (login/password) on the RunDeck instance
+101 *
+102 * @throws RundeckApiLoginException if the login fails
+103 */
+104publicvoid testCredentials() throws RundeckApiLoginException {
+105newApiCall(this).testCredentials();
+106 }
+107
+108/*
+109 * Projects
+110 */
+111
+112/**
+113 * List all projects
+114 *
+115 * @return a {@link List} of {@link RundeckProject} : might be empty, but won't be null
+116 * @throws RundeckApiException in case of error when calling the API
+117 * @throws RundeckApiLoginException if the login failed
+118 */
+119public List<RundeckProject> getProjects() throws RundeckApiException, RundeckApiLoginException {
+120returnnewApiCall(this).get(newApiPathBuilder("/projects"),
+121new ListParser<RundeckProject>(newProjectParser(), "result/projects/project"));
+122 }
+123
+124/**
+125 * Get the definition of a single project, identified by the given name
+126 *
+127 * @param projectName name of the project - mandatory
+128 * @return a {@link RundeckProject} instance - won't be null
+129 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
+130 * @throws RundeckApiLoginException if the login failed
+131 * @throws IllegalArgumentException if the projectName is blank (null, empty or whitespace)
+132 */
+133publicRundeckProject getProject(String projectName) throws RundeckApiException, RundeckApiLoginException,
+134 IllegalArgumentException {
+135 AssertUtil.notBlank(projectName, "projectName is mandatory to get the details of a project !");
+136returnnewApiCall(this).get(newApiPathBuilder("/project/", projectName),
+137newProjectParser("result/projects/project"));
+138 }
+139
+140/*
+141 * Jobs
+142 */
+143
+144/**
+145 * List all jobs (for all projects)
+146 *
+147 * @return a {@link List} of {@link RundeckJob} : might be empty, but won't be null
+148 * @throws RundeckApiException in case of error when calling the API
+149 * @throws RundeckApiLoginException if the login failed
+150 */
+151public List<RundeckJob> getJobs() throws RundeckApiException, RundeckApiLoginException {
+152 List<RundeckJob> jobs = new ArrayList<RundeckJob>();
+153for (RundeckProject project : getProjects()) {
+154 jobs.addAll(getJobs(project.getName()));
+155 }
+156return jobs;
+157 }
+158
+159/**
+160 * List all jobs that belongs to the given project
+161 *
+162 * @param project name of the project - mandatory
+163 * @return a {@link List} of {@link RundeckJob} : might be empty, but won't be null
+164 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
+165 * @throws RundeckApiLoginException if the login failed
+166 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
+167 * @see #getJobs(String, String, String, String...)
+168 */
+169public List<RundeckJob> getJobs(String project) throws RundeckApiException, RundeckApiLoginException,
+170 IllegalArgumentException {
+171return getJobs(project, null, null, new String[0]);
+172 }
+173
+174/**
+175 * List the jobs that belongs to the given project, and matches the given criteria (jobFilter, groupPath and jobIds)
+176 *
+177 * @param project name of the project - mandatory
+178 * @param jobFilter a filter for the job Name - optional
+179 * @param groupPath a group or partial group path to include all jobs within that group path - optional
+180 * @param jobIds a list of Job IDs to include - optional
+181 * @return a {@link List} of {@link RundeckJob} : might be empty, but won't be null
+182 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
+183 * @throws RundeckApiLoginException if the login failed
+184 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
+185 * @see #getJobs(String)
+186 */
+187public List<RundeckJob> getJobs(String project, String jobFilter, String groupPath, String... jobIds)
+188throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
+189 AssertUtil.notBlank(project, "project is mandatory to get all jobs !");
+190returnnewApiCall(this).get(newApiPathBuilder("/jobs").param("project", project)
+191 .param("jobFilter", jobFilter)
+192 .param("groupPath", groupPath)
+193 .param("idlist", StringUtils.join(jobIds, ",")),
+194new ListParser<RundeckJob>(newJobParser(), "result/jobs/job"));
+195 }
+196
+197/**
+198 * Find a job, identified by its project, group and name. Note that the groupPath is optional, as a job does not
+199 * need to belong to a group (either pass null, or an empty string).
+200 *
+201 * @param project name of the project - mandatory
+202 * @param groupPath group to which the job belongs (if it belongs to a group) - optional
+203 * @param name of the job to find - mandatory
+204 * @return a {@link RundeckJob} instance - null if not found
+205 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
+206 * @throws RundeckApiLoginException if the login failed
+207 * @throws IllegalArgumentException if the project or the name is blank (null, empty or whitespace)
+208 */
+209publicRundeckJob findJob(String project, String groupPath, String name) throws RundeckApiException,
+210 RundeckApiLoginException, IllegalArgumentException {
+211 AssertUtil.notBlank(project, "project is mandatory to find a job !");
+212 AssertUtil.notBlank(name, "job name is mandatory to find a job !");
+213 List<RundeckJob> jobs = getJobs(project, name, groupPath, new String[0]);
+214return jobs.isEmpty() ? null : jobs.get(0);
+215 }
+216
+217/**
+218 * Get the definition of a single job, identified by the given ID
+219 *
+220 * @param jobId identifier of the job - mandatory
+221 * @return a {@link RundeckJob} instance - won't be null
+222 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
+223 * @throws RundeckApiLoginException if the login failed
+224 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
+225 */
+226publicRundeckJob getJob(String jobId) throws RundeckApiException, RundeckApiLoginException,
+227 IllegalArgumentException {
+228 AssertUtil.notBlank(jobId, "jobId is mandatory to get the details of a job !");
+229returnnewApiCall(this).get(newApiPathBuilder("/job/", jobId), newJobParser("joblist/job"));
+230 }
+231
+232/**
+233 * Trigger the execution of a RunDeck job (identified by the given ID), and return immediately (without waiting the
+234 * end of the job execution)
+235 *
+236 * @param jobId identifier of the job - mandatory
+237 * @return a {@link RundeckExecution} instance for the newly created (and running) execution - won't be null
+238 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
+239 * @throws RundeckApiLoginException if the login failed
+240 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
+241 * @see #triggerJob(String, Properties, Properties)
+242 * @see #runJob(String)
+243 */
+244publicRundeckExecution triggerJob(String jobId) throws RundeckApiException, RundeckApiLoginException,
+245 IllegalArgumentException {
+246return triggerJob(jobId, null);
+247 }
+248
+249/**
+250 * Trigger the execution of a RunDeck job (identified by the given ID), and return immediately (without waiting the
+251 * end of the job execution)
+252 *
+253 * @param jobId identifier of the job - mandatory
+254 * @param options of the job - optional. See {@link OptionsBuilder}.
+255 * @return a {@link RundeckExecution} instance for the newly created (and running) execution - won't be null
+256 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
+257 * @throws RundeckApiLoginException if the login failed
+258 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
+259 * @see #triggerJob(String, Properties, Properties)
+260 * @see #runJob(String, Properties)
+261 */
+262publicRundeckExecution triggerJob(String jobId, Properties options) throws RundeckApiException,
+263 RundeckApiLoginException, IllegalArgumentException {
+264return triggerJob(jobId, options, null);
+265 }
+266
+267/**
+268 * Trigger the execution of a RunDeck job (identified by the given ID), and return immediately (without waiting the
+269 * end of the job execution)
+270 *
+271 * @param jobId identifier of the job - mandatory
+272 * @param options of the job - optional. See {@link OptionsBuilder}.
+273 * @param nodeFilters for overriding the nodes on which the job will be executed - optional. See
+274 * {@link NodeFiltersBuilder}
+275 * @return a {@link RundeckExecution} instance for the newly created (and running) execution - won't be null
+276 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
+277 * @throws RundeckApiLoginException if the login failed
+278 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
+279 * @see #triggerJob(String)
+280 * @see #runJob(String, Properties, Properties)
+281 */
+282publicRundeckExecution triggerJob(String jobId, Properties options, Properties nodeFilters)
+283throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
+284 AssertUtil.notBlank(jobId, "jobId is mandatory to trigger a job !");
+285returnnewApiCall(this).get(newApiPathBuilder("/job/", jobId, "/run").param("argString",
+286 ParametersUtil.generateArgString(options))
+287 .nodeFilters(nodeFilters),
+288newExecutionParser("result/executions/execution"));
+289 }
+290
+291/**
+292 * Run a RunDeck job (identified by the given ID), and wait until its execution is finished (or aborted) to return.
+293 * We will poll the RunDeck server at regular interval (every 5 seconds) to know if the execution is finished (or
+294 * aborted) or is still running.
+295 *
+296 * @param jobId identifier of the job - mandatory
+297 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
+298 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
+299 * @throws RundeckApiLoginException if the login failed
+300 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
+301 * @see #triggerJob(String)
+302 * @see #runJob(String, Properties, Properties, long, TimeUnit)
+303 */
+304publicRundeckExecution runJob(String jobId) throws RundeckApiException, RundeckApiLoginException,
+305 IllegalArgumentException {
+306return runJob(jobId, null);
+307 }
+308
+309/**
+310 * Run a RunDeck job (identified by the given ID), and wait until its execution is finished (or aborted) to return.
+311 * We will poll the RunDeck server at regular interval (every 5 seconds) to know if the execution is finished (or
+312 * aborted) or is still running.
+313 *
+314 * @param jobId identifier of the job - mandatory
+315 * @param options of the job - optional. See {@link OptionsBuilder}.
+316 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
+317 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
+318 * @throws RundeckApiLoginException if the login failed
+319 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
+320 * @see #triggerJob(String, Properties)
+321 * @see #runJob(String, Properties, Properties, long, TimeUnit)
+322 */
+323publicRundeckExecution runJob(String jobId, Properties options) throws RundeckApiException,
+324 RundeckApiLoginException, IllegalArgumentException {
+325return runJob(jobId, options, null);
+326 }
+327
+328/**
+329 * Run a RunDeck job (identified by the given ID), and wait until its execution is finished (or aborted) to return.
+330 * We will poll the RunDeck server at regular interval (every 5 seconds) to know if the execution is finished (or
+331 * aborted) or is still running.
+332 *
+333 * @param jobId identifier of the job - mandatory
+334 * @param options of the job - optional. See {@link OptionsBuilder}.
+335 * @param nodeFilters for overriding the nodes on which the job will be executed - optional. See
+336 * {@link NodeFiltersBuilder}
+337 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
+338 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
+339 * @throws RundeckApiLoginException if the login failed
+340 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
+341 * @see #triggerJob(String, Properties, Properties)
+342 * @see #runJob(String, Properties, Properties, long, TimeUnit)
+343 */
+344publicRundeckExecution runJob(String jobId, Properties options, Properties nodeFilters)
+345throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
+346return runJob(jobId, options, nodeFilters, 5, TimeUnit.SECONDS);
+347 }
+348
+349/**
+350 * Run a RunDeck job (identified by the given ID), and wait until its execution is finished (or aborted) to return.
+351 * We will poll the RunDeck server at regular interval (configured by the poolingInterval/poolingUnit couple) to
+352 * know if the execution is finished (or aborted) or is still running.
+353 *
+354 * @param jobId identifier of the job - mandatory
+355 * @param options of the job - optional. See {@link OptionsBuilder}.
+356 * @param poolingInterval for checking the status of the execution. Must be > 0.
+357 * @param poolingUnit unit (seconds, milli-seconds, ...) of the interval. Default to seconds.
+358 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
+359 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
+360 * @throws RundeckApiLoginException if the login failed
+361 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
+362 * @see #triggerJob(String, Properties)
+363 * @see #runJob(String, Properties, Properties, long, TimeUnit)
+364 */
+365publicRundeckExecution runJob(String jobId, Properties options, long poolingInterval, TimeUnit poolingUnit)
+366throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
+367return runJob(jobId, options, null, poolingInterval, poolingUnit);
+368 }
+369
+370/**
+371 * Run a RunDeck job (identified by the given ID), and wait until its execution is finished (or aborted) to return.
+372 * We will poll the RunDeck server at regular interval (configured by the poolingInterval/poolingUnit couple) to
+373 * know if the execution is finished (or aborted) or is still running.
+374 *
+375 * @param jobId identifier of the job - mandatory
+376 * @param options of the job - optional. See {@link OptionsBuilder}.
+377 * @param nodeFilters for overriding the nodes on which the job will be executed - optional. See
+378 * {@link NodeFiltersBuilder}
+379 * @param poolingInterval for checking the status of the execution. Must be > 0.
+380 * @param poolingUnit unit (seconds, milli-seconds, ...) of the interval. Default to seconds.
+381 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
+382 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
+383 * @throws RundeckApiLoginException if the login failed
+384 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
+385 * @see #triggerJob(String, Properties)
+386 * @see #runJob(String, Properties, Properties, long, TimeUnit)
+387 */
+388publicRundeckExecution runJob(String jobId, Properties options, Properties nodeFilters, long poolingInterval,
+389 TimeUnit poolingUnit) throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
+390if (poolingInterval <= 0) {
+391 poolingInterval = 5;
+392 poolingUnit = TimeUnit.SECONDS;
+393 }
+394if (poolingUnit == null) {
+395 poolingUnit = TimeUnit.SECONDS;
+396 }
+397
+398RundeckExecution execution = triggerJob(jobId, options, nodeFilters);
+399while (ExecutionStatus.RUNNING.equals(execution.getStatus())) {
+400try {
+401 Thread.sleep(poolingUnit.toMillis(poolingInterval));
+402 } catch (InterruptedException e) {
+403break;
+404 }
+405 execution = getExecution(execution.getId());
+406 }
+407return execution;
+408 }
+409
+410/*
+411 * Ad-hoc commands
+412 */
+413
+414/**
+415 * Trigger the execution of an ad-hoc command, and return immediately (without waiting the end of the execution).
+416 * The command will not be dispatched to nodes, but be executed on the RunDeck server.
+417 *
+418 * @param project name of the project - mandatory
+419 * @param command to be executed - mandatory
+420 * @return a {@link RundeckExecution} instance for the newly created (and running) execution - won't be null
+421 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
+422 * @throws RundeckApiLoginException if the login failed
+423 * @throws IllegalArgumentException if the project or command is blank (null, empty or whitespace)
+424 * @see #triggerAdhocCommand(String, String, Properties)
+425 * @see #runAdhocCommand(String, String)
+426 */
+427publicRundeckExecution triggerAdhocCommand(String project, String command) throws RundeckApiException,
+428 RundeckApiLoginException, IllegalArgumentException {
+429return triggerAdhocCommand(project, command, null);
+430 }
+431
+432/**
+433 * Trigger the execution of an ad-hoc command, and return immediately (without waiting the end of the execution).
+434 * The command will be dispatched to nodes, accordingly to the nodeFilters parameter.
+435 *
+436 * @param project name of the project - mandatory
+437 * @param command to be executed - mandatory
+438 * @param nodeFilters for selecting nodes on which the command will be executed. See {@link NodeFiltersBuilder}
+439 * @return a {@link RundeckExecution} instance for the newly created (and running) execution - won't be null
+440 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
+441 * @throws RundeckApiLoginException if the login failed
+442 * @throws IllegalArgumentException if the project or command is blank (null, empty or whitespace)
+443 * @see #triggerAdhocCommand(String, String)
+444 * @see #runAdhocCommand(String, String, Properties)
+445 */
+446publicRundeckExecution triggerAdhocCommand(String project, String command, Properties nodeFilters)
+447throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
+448 AssertUtil.notBlank(project, "project is mandatory to trigger an ad-hoc command !");
+449 AssertUtil.notBlank(command, "command is mandatory to trigger an ad-hoc command !");
+450RundeckExecution execution = newApiCall(this).get(newApiPathBuilder("/run/command").param("project", project)
+451 .param("exec", command)
+452 .nodeFilters(nodeFilters),
+453newExecutionParser("result/execution"));
+454// the first call just returns the ID of the execution, so we need another call to get a "real" execution
+455return getExecution(execution.getId());
+456 }
+457
+458/**
+459 * Run an ad-hoc command, and wait until its execution is finished (or aborted) to return. We will poll the RunDeck
+460 * server at regular interval (every 5 seconds) to know if the execution is finished (or aborted) or is still
+461 * running. The command will not be dispatched to nodes, but be executed on the RunDeck server.
+462 *
+463 * @param project name of the project - mandatory
+464 * @param command to be executed - mandatory
+465 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
+466 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
+467 * @throws RundeckApiLoginException if the login failed
+468 * @throws IllegalArgumentException if the project or command is blank (null, empty or whitespace)
+469 * @see #runAdhocCommand(String, String, Properties, long, TimeUnit)
+470 * @see #triggerAdhocCommand(String, String)
+471 */
+472publicRundeckExecution runAdhocCommand(String project, String command) throws RundeckApiException,
+473 RundeckApiLoginException, IllegalArgumentException {
+474return runAdhocCommand(project, command, null);
+475 }
+476
+477/**
+478 * Run an ad-hoc command, and wait until its execution is finished (or aborted) to return. We will poll the RunDeck
+479 * server at regular interval (configured by the poolingInterval/poolingUnit couple) to know if the execution is
+480 * finished (or aborted) or is still running. The command will not be dispatched to nodes, but be executed on the
+481 * RunDeck server.
+482 *
+483 * @param project name of the project - mandatory
+484 * @param command to be executed - mandatory
+485 * @param poolingInterval for checking the status of the execution. Must be > 0.
+486 * @param poolingUnit unit (seconds, milli-seconds, ...) of the interval. Default to seconds.
+487 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
+488 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
+489 * @throws RundeckApiLoginException if the login failed
+490 * @throws IllegalArgumentException if the project or command is blank (null, empty or whitespace)
+491 * @see #runAdhocCommand(String, String, Properties, long, TimeUnit)
+492 * @see #triggerAdhocCommand(String, String)
+493 */
+494publicRundeckExecution runAdhocCommand(String project, String command, long poolingInterval, TimeUnit poolingUnit)
+495throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
+496return runAdhocCommand(project, command, null, poolingInterval, poolingUnit);
+497 }
+498
+499/**
+500 * Run an ad-hoc command, and wait until its execution is finished (or aborted) to return. We will poll the RunDeck
+501 * server at regular interval (every 5 seconds) to know if the execution is finished (or aborted) or is still
+502 * running. The command will be dispatched to nodes, accordingly to the nodeFilters parameter.
+503 *
+504 * @param project name of the project - mandatory
+505 * @param command to be executed - mandatory
+506 * @param nodeFilters for selecting nodes on which the command will be executed. See {@link NodeFiltersBuilder}
+507 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
+508 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
+509 * @throws RundeckApiLoginException if the login failed
+510 * @throws IllegalArgumentException if the project or command is blank (null, empty or whitespace)
+511 * @see #runAdhocCommand(String, String, Properties, long, TimeUnit)
+512 * @see #triggerAdhocCommand(String, String, Properties)
+513 */
+514publicRundeckExecution runAdhocCommand(String project, String command, Properties nodeFilters)
+515throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
+516return runAdhocCommand(project, command, nodeFilters, 5, TimeUnit.SECONDS);
+517 }
+518
+519/**
+520 * Run an ad-hoc command, and wait until its execution is finished (or aborted) to return. We will poll the RunDeck
+521 * server at regular interval (configured by the poolingInterval/poolingUnit couple) to know if the execution is
+522 * finished (or aborted) or is still running. The command will be dispatched to nodes, accordingly to the
+523 * nodeFilters parameter.
+524 *
+525 * @param project name of the project - mandatory
+526 * @param command to be executed - mandatory
+527 * @param nodeFilters for selecting nodes on which the command will be executed. See {@link NodeFiltersBuilder}
+528 * @param poolingInterval for checking the status of the execution. Must be > 0.
+529 * @param poolingUnit unit (seconds, milli-seconds, ...) of the interval. Default to seconds.
+530 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
+531 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
+532 * @throws RundeckApiLoginException if the login failed
+533 * @throws IllegalArgumentException if the project or command is blank (null, empty or whitespace)
+534 * @see #triggerAdhocCommand(String, String, Properties)
+535 */
+536publicRundeckExecution runAdhocCommand(String project, String command, Properties nodeFilters,
+537long poolingInterval, TimeUnit poolingUnit) throws RundeckApiException, RundeckApiLoginException,
+538 IllegalArgumentException {
+539if (poolingInterval <= 0) {
+540 poolingInterval = 5;
+541 poolingUnit = TimeUnit.SECONDS;
+542 }
+543if (poolingUnit == null) {
+544 poolingUnit = TimeUnit.SECONDS;
+545 }
+546
+547RundeckExecution execution = triggerAdhocCommand(project, command, nodeFilters);
+548while (ExecutionStatus.RUNNING.equals(execution.getStatus())) {
+549try {
+550 Thread.sleep(poolingUnit.toMillis(poolingInterval));
+551 } catch (InterruptedException e) {
+552break;
+553 }
+554 execution = getExecution(execution.getId());
+555 }
+556return execution;
+557 }
+558
+559/*
+560 * Executions
+561 */
+562
+563/**
+564 * Get all running executions (for all projects)
+565 *
+566 * @return a {@link List} of {@link RundeckExecution} : might be empty, but won't be null
+567 * @throws RundeckApiException in case of error when calling the API
+568 * @throws RundeckApiLoginException if the login failed
+569 */
+570public List<RundeckExecution> getRunningExecutions() throws RundeckApiException, RundeckApiLoginException {
+571 List<RundeckExecution> executions = new ArrayList<RundeckExecution>();
+572for (RundeckProject project : getProjects()) {
+573 executions.addAll(getRunningExecutions(project.getName()));
+574 }
+575return executions;
+576 }
+577
+578/**
+579 * Get the running executions for the given project
+580 *
+581 * @param project name of the project - mandatory
+582 * @return a {@link List} of {@link RundeckExecution} : might be empty, but won't be null
+583 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
+584 * @throws RundeckApiLoginException if the login failed
+585 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
+586 */
+587public List<RundeckExecution> getRunningExecutions(String project) throws RundeckApiException,
+588 RundeckApiLoginException, IllegalArgumentException {
+589 AssertUtil.notBlank(project, "project is mandatory get all running executions !");
+590returnnewApiCall(this).get(newApiPathBuilder("/executions/running").param("project", project),
+591new ListParser<RundeckExecution>(newExecutionParser(),
+592"result/executions/execution"));
+593 }
+594
+595/**
+596 * Get the executions of the given job
+597 *
+598 * @param jobId identifier of the job - mandatory
+599 * @return a {@link List} of {@link RundeckExecution} : might be empty, but won't be null
+600 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
+601 * @throws RundeckApiLoginException if the login failed
+602 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
+603 */
+604public List<RundeckExecution> getJobExecutions(String jobId) throws RundeckApiException, RundeckApiLoginException,
+605 IllegalArgumentException {
+606return getJobExecutions(jobId, null);
+607 }
+608
+609/**
+610 * Get the executions of the given job
+611 *
+612 * @param jobId identifier of the job - mandatory
+613 * @param status of the executions - optional (null for all)
+614 * @return a {@link List} of {@link RundeckExecution} : might be empty, but won't be null
+615 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
+616 * @throws RundeckApiLoginException if the login failed
+617 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
+618 */
+619public List<RundeckExecution> getJobExecutions(String jobId, ExecutionStatus status) throws RundeckApiException,
+620 RundeckApiLoginException, IllegalArgumentException {
+621return getJobExecutions(jobId, status, null, null);
+622 }
+623
+624/**
+625 * Get the executions of the given job
+626 *
+627 * @param jobId identifier of the job - mandatory
+628 * @param status of the executions - optional (null for all)
+629 * @param max number of results to return - optional (null for all)
+630 * @param offset the 0-indexed offset for the first result to return - optional
+631 * @return a {@link List} of {@link RundeckExecution} : might be empty, but won't be null
+632 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
+633 * @throws RundeckApiLoginException if the login failed
+634 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
+635 */
+636public List<RundeckExecution> getJobExecutions(String jobId, ExecutionStatus status, Long max, Long offset)
+637throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
+638 AssertUtil.notBlank(jobId, "jobId is mandatory to get the executions of a job !");
+639returnnewApiCall(this).get(newApiPathBuilder("/job/", jobId, "/executions").param("status",
+640 status != null ? StringUtils.lowerCase(status.toString()) : null)
+641 .param("max", max)
+642 .param("offset", offset),
+643new ListParser<RundeckExecution>(newExecutionParser(),
+644"result/executions/execution"));
645 }
646647/**
@@ -735,7 +735,7 @@
725 AssertUtil.notBlank(project, "project is mandatory to get all nodes !");
726returnnewApiCall(this).get(newApiPathBuilder("/resources").param("project", project)
727 .nodeFilters(nodeFilters),
-728newNodesParser("project/node"));
+728new ListParser<RundeckNode>(newNodeParser(), "project/node"));
729 }
730731/**
diff --git a/xref/org/rundeck/api/parser/ListParser.html b/xref/org/rundeck/api/parser/ListParser.html
new file mode 100644
index 0000000..e48972b
--- /dev/null
+++ b/xref/org/rundeck/api/parser/ListParser.html
@@ -0,0 +1,72 @@
+
+
+
+
+ListParser xref
+
+
+
+
+
+1/*
+2 * Copyright 2011 Vincent Behar
+3 *
+4 * Licensed under the Apache License, Version 2.0 (the "License");
+5 * you may not use this file except in compliance with the License.
+6 * You may obtain a copy of the License at
+7 *
+8 * http://www.apache.org/licenses/LICENSE-2.0
+9 *
+10 * Unless required by applicable law or agreed to in writing, software
+11 * distributed under the License is distributed on an "AS IS" BASIS,
+12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+13 * See the License for the specific language governing permissions and
+14 * limitations under the License.
+15 */
+16package org.rundeck.api.parser;
+17
+18import java.util.ArrayList;
+19import java.util.List;
+20import org.dom4j.Node;
+21
+22/**
+23 * Parser for a {@link List} of elements
+24 *
+25 * @author Vincent Behar
+26 */
+27publicclass ListParser<T> implements XmlNodeParser<List<T>> {
+28
+29privatefinal XmlNodeParser<T> parser;
+30
+31privatefinal String xpath;
+32
+33/**
+34 * @param parser for an individual element
+35 * @param xpath of the elements
+36 */
+37publicListParser(XmlNodeParser<T> parser, String xpath) {
+38super();
+39this.parser = parser;
+40this.xpath = xpath;
+41 }
+42
+43 @Override
+44public List<T> parseXmlNode(Node node) {
+45 List<T> elements = new ArrayList<T>();
+46
+47 @SuppressWarnings("unchecked")
+48 List<Node> elementNodes = node.selectNodes(xpath);
+49
+50for (Node elementNode : elementNodes) {
+51 T element = parser.parseXmlNode(elementNode);
+52 elements.add(element);
+53 }
+54
+55return elements;
+56 }
+57
+58 }
+