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 */
16 package org.rundeck.api;
17
18 import org.apache.commons.io.FileUtils;
19 import org.apache.commons.io.IOUtils;
20 import org.apache.commons.lang.StringUtils;
21 import org.dom4j.Document;
22 import org.rundeck.api.RundeckApiException.RundeckApiLoginException;
23 import org.rundeck.api.RundeckApiException.RundeckApiTokenException;
24 import org.rundeck.api.domain.*;
25 import org.rundeck.api.domain.RundeckExecution.ExecutionStatus;
26 import org.rundeck.api.generator.DeleteExecutionsGenerator;
27 import org.rundeck.api.generator.ProjectConfigGenerator;
28 import org.rundeck.api.generator.ProjectConfigPropertyGenerator;
29 import org.rundeck.api.generator.ProjectGenerator;
30 import org.rundeck.api.parser.*;
31 import org.rundeck.api.query.ExecutionQuery;
32 import org.rundeck.api.util.AssertUtil;
33 import org.rundeck.api.util.PagedResults;
34 import org.rundeck.api.util.ParametersUtil;
35
36 import java.io.*;
37 import java.util.*;
38 import java.util.concurrent.TimeUnit;
39
40 /**
41 * Rundeck API client.
42 * <p>
43 * There are three methods for authentication : login-based or token-based or session-based.
44 * Login authentication requires
45 * both a "login" and a "password". Token-based requires a "token" (also called "auth-token"). See the Rundeck
46 * documentation for generating such a token.</p>
47 * <p>
48 * Session-based authentication allows re-use of a previous login session. See {@link #testAuth()}.
49 * </p>
50 * <br>
51 * Usage : <br>
52 * <code>
53 * <pre>
54 * // using login-based authentication :
55 * RundeckClient rundeck = RundeckClient.builder()
56 * .url("http://localhost:4440")
57 * .login("admin", "admin").build();
58 * // or for a token-based authentication :
59 * RundeckClient rundeck = RundeckClient.builder()
60 * .url("http://localhost:4440")
61 * .token("PDDNKo5VE29kpk4prOUDr2rsKdRkEvsD").build();
62 *
63 * List<RundeckProject> projects = rundeck.getProjects();
64 *
65 * RundeckJob job = rundeck.findJob("my-project", "main-group/sub-group", "job-name");
66 * RundeckExecution execution = rundeck.triggerJob(job.getId(),
67 * new OptionsBuilder().addOption("version", "1.2.0").toProperties());
68 *
69 * List<RundeckExecution> runningExecutions = rundeck.getRunningExecutions("my-project");
70 *
71 * rundeck.exportJobsToFile("/tmp/jobs.xml", FileType.XML, "my-project");
72 * rundeck.importJobs("/tmp/jobs.xml", FileType.XML);
73 * </pre>
74 * </code>
75 *
76 * @author Vincent Behar
77 */
78 public class RundeckClient implements Serializable {
79
80 private static final long serialVersionUID = 1L;
81 public static final String JOBS_IMPORT = "/jobs/import";
82 public static final String STORAGE_ROOT_PATH = "/storage/";
83 public static final String STORAGE_KEYS_PATH = "keys/";
84
85 /**
86 * Supported version numbers
87 */
88 public static enum Version {
89 V5(5),
90 V6(6),
91 V7(7),
92 V8(8),
93 V9(9),
94 V10(10),
95 V11(11),
96 V12(12),
97 V13(13),
98 ;
99
100 private int versionNumber;
101
102 Version(final int i) {
103 versionNumber = i;
104 }
105
106 public int getVersionNumber() {
107 return versionNumber;
108 }
109 }
110 /** Version of the API supported */
111 public static final transient int API_VERSION = Version.V13.getVersionNumber();
112
113 private static final String API = "/api/";
114
115 /** End-point of the API */
116 public static final transient String API_ENDPOINT = API + API_VERSION;
117
118 /** Default value for the "pooling interval" used when running jobs/commands/scripts */
119 public static final transient long DEFAULT_POOLING_INTERVAL = 5;
120
121 /** Default unit of the "pooling interval" used when running jobs/commands/scripts */
122 public static final TimeUnit DEFAULT_POOLING_UNIT = TimeUnit.SECONDS;
123
124 /** URL of the Rundeck instance ("http://localhost:4440" target="alexandria_uri">http://localhost:4440", "http://rundeck.your-compagny.com/", etc) */
125 private final String url;
126
127 private int apiVersion = API_VERSION;
128
129 private String token;
130
131 private String login;
132
133 private String password;
134
135 private String sessionID;
136 private boolean sslHostnameVerifyAllowAll = false;
137 private boolean sslCertificateTrustAllowSelfSigned = false;
138 private boolean systemProxyEnabled = false;
139
140 void setToken(String token) {
141 this.token = token;
142 }
143
144 void setLogin(String login) {
145 this.login = login;
146 }
147
148 void setPassword(String password) {
149 this.password = password;
150 }
151
152 void setSessionID(String sessionID) {
153 this.sessionID = sessionID;
154 }
155
156 int getApiVersion() {
157 return (apiVersion > 0 ? apiVersion : API_VERSION);
158 }
159
160 void setApiVersion(int apiVersion) {
161 this.apiVersion = (apiVersion > 0 ? apiVersion : API_VERSION);
162 }
163
164 void setApiVersion(Version apiVersion) {
165 setApiVersion(apiVersion.getVersionNumber());
166 }
167
168 String getApiEndpoint() {
169 return API + getApiVersion();
170 }
171
172 boolean isSslHostnameVerifyAllowAll() {
173 return sslHostnameVerifyAllowAll;
174 }
175
176 void setSslHostnameVerifyAllowAll(boolean sslHostnameVerifyAllowAll) {
177 this.sslHostnameVerifyAllowAll = sslHostnameVerifyAllowAll;
178 }
179
180 boolean isSslCertificateTrustAllowSelfSigned() {
181 return sslCertificateTrustAllowSelfSigned;
182 }
183
184 void setSslCertificateTrustAllowSelfSigned(boolean sslCertificateTrustAllowSelfSigned) {
185 this.sslCertificateTrustAllowSelfSigned = sslCertificateTrustAllowSelfSigned;
186 }
187 boolean isSystemProxyEnabled() {
188 return systemProxyEnabled;
189 }
190
191 void setSystemProxyEnabled(boolean systemProxyEnabled) {
192 this.systemProxyEnabled = systemProxyEnabled;
193 }
194
195
196 /**
197 * Used by RundeckClientBuilder
198 */
199 RundeckClient(final String url) throws IllegalArgumentException {
200 AssertUtil.notBlank(url, "The Rundeck URL is mandatory !");
201 this.url=url;
202 }
203
204 /**
205 * Create a builder for RundeckClient
206 */
207 public static RundeckClientBuilder builder() {
208 return new RundeckClientBuilder();
209 }
210
211 /**
212 * Try to "ping" the Rundeck instance to see if it is alive
213 *
214 * @throws RundeckApiException if the ping fails
215 */
216 public void ping() throws RundeckApiException {
217 new ApiCall(this).ping();
218 }
219
220 /**
221 * Test the authentication on the Rundeck instance.
222 *
223 * @return sessionID if doing username+password login and it succeeded
224 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
225 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
226 */
227 public String testAuth() throws RundeckApiLoginException, RundeckApiTokenException {
228 return (new ApiCall(this)).testAuth();
229 }
230
231
232 /*
233 * Projects
234 */
235
236 private ProjectParser createProjectParser() {
237 return createProjectParser(null);
238 }
239
240 private ProjectParser createProjectParser(final String xpath) {
241 return new ProjectParserV11(xpath);
242 }
243
244 /**
245 * List all projects
246 *
247 * @return a {@link List} of {@link RundeckProject} : might be empty, but won't be null
248 * @throws RundeckApiException in case of error when calling the API
249 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
250 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
251 */
252 public List<RundeckProject> getProjects() throws RundeckApiException, RundeckApiLoginException,
253 RundeckApiTokenException {
254 return new ApiCall(this).get(new ApiPathBuilder("/projects"),
255 new ListParser<>(
256 createProjectParser(),
257 "/projects/project"
258 ));
259 }
260
261 /**
262 * Get the definition of a single project, identified by the given name
263 *
264 * @param projectName name of the project - mandatory
265 * @return a {@link RundeckProject} instance - won't be null
266 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
267 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
268 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
269 * @throws IllegalArgumentException if the projectName is blank (null, empty or whitespace)
270 */
271 public RundeckProject getProject(String projectName) throws RundeckApiException, RundeckApiLoginException,
272 RundeckApiTokenException, IllegalArgumentException {
273 AssertUtil.notBlank(projectName, "projectName is mandatory to get the details of a project !");
274 return new ApiCall(this).get(new ApiPathBuilder("/project/", projectName),
275 createProjectParser(
276 (getApiVersion() < Version.V11.getVersionNumber()
277 ? "/projects/project"
278 : "/project"
279 )));
280 }
281
282 /**
283 * Create a new project, and return the new definition
284 *
285 * @param projectName name of the project - mandatory
286 * @param configuration project configuration properties
287 *
288 * @return a {@link RundeckProject} instance - won't be null
289 *
290 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
291 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
292 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
293 * @throws IllegalArgumentException if the projectName is blank (null, empty or whitespace)
294 */
295 public RundeckProject createProject(String projectName, Map<String, String> configuration) throws
296 RundeckApiException, RundeckApiLoginException,
297 RundeckApiTokenException, IllegalArgumentException {
298
299 AssertUtil.notBlank(projectName, "projectName is mandatory to create a project !");
300 return new ApiCall(this)
301 .post(new ApiPathBuilder("/projects").xml(
302 projectDocument(projectName, configuration)
303 ), createProjectParser(
304 (getApiVersion() < Version.V11.getVersionNumber()
305 ? "/projects/project"
306 : "/project"
307 )));
308 }
309 /**
310 * Delete a project
311 *
312 * @param projectName name of the project - mandatory
313 *
314 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
315 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
316 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
317 * @throws IllegalArgumentException if the projectName is blank (null, empty or whitespace)
318 */
319 public void deleteProject(String projectName) throws
320 RundeckApiException, RundeckApiLoginException,
321 RundeckApiTokenException, IllegalArgumentException {
322
323 AssertUtil.notBlank(projectName, "projectName is mandatory to create a project !");
324 new ApiCall(this).delete(new ApiPathBuilder("/project/", projectName));
325 }
326 /**
327 * Convenience method to export the archive of a project to the specified file.
328 *
329 * @param projectName name of the project - mandatory
330 * @param out file to write to
331 * @return number of bytes written to the stream
332 *
333 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
334 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
335 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
336 * @throws IllegalArgumentException if the projectName is blank (null, empty or whitespace)
337 */
338 public int exportProject(final String projectName, final File out) throws
339 RundeckApiException, RundeckApiLoginException,
340 RundeckApiTokenException, IllegalArgumentException, IOException {
341 final FileOutputStream fileOutputStream = new FileOutputStream(out);
342 try {
343 return exportProject(projectName, fileOutputStream);
344 }finally {
345 fileOutputStream.close();
346 }
347 }
348 /**
349 * Export the archive of a project to the specified outputstream
350 *
351 * @param projectName name of the project - mandatory
352 * @return number of bytes written to the stream
353 *
354 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
355 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
356 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
357 * @throws IllegalArgumentException if the projectName is blank (null, empty or whitespace)
358 */
359 public int exportProject(String projectName, OutputStream out) throws
360 RundeckApiException, RundeckApiLoginException,
361 RundeckApiTokenException, IllegalArgumentException, IOException {
362
363 AssertUtil.notBlank(projectName, "projectName is mandatory to export a project archive!");
364 return new ApiCall(this).get(
365 new ApiPathBuilder("/project/", projectName, "/export")
366 .accept("application/zip"),
367 out);
368 }
369
370 /**
371 * Import a archive file to the specified project.
372 *
373 * @param projectName name of the project - mandatory
374 * @param archiveFile zip archive file
375 * @param includeExecutions if true, import executions defined in the archive, otherwise skip them
376 * @param preserveJobUuids if true, do not remove UUIDs from imported jobs, otherwise remove them
377 *
378 * @return Result of the import request, may contain a list of import error messages
379 *
380 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
381 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
382 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
383 * @throws IllegalArgumentException if the projectName is blank (null, empty or whitespace)
384 */
385 public ArchiveImport importArchive(final String projectName, final File archiveFile,
386 final boolean includeExecutions, final boolean preserveJobUuids) throws
387 RundeckApiException, RundeckApiLoginException,
388 RundeckApiTokenException, IllegalArgumentException, IOException {
389
390 AssertUtil.notBlank(projectName, "projectName is mandatory to import a project archive!");
391 AssertUtil.notNull(archiveFile, "archiveFile is mandatory to import a project archive!"); ;
392 return callImportProject(projectName, includeExecutions, preserveJobUuids,
393 new ApiPathBuilder().content("application/zip", archiveFile));
394 }
395
396 private ArchiveImport callImportProject(final String projectName, final boolean includeExecutions, final boolean preserveJobUuids,
397 final ApiPathBuilder param) {
398 param.paths("/project/", projectName, "/import")
399 .param("importExecutions", includeExecutions)
400 .param("jobUuidOption", preserveJobUuids ? "preserve" : "remove");
401 return new ApiCall(this).put(
402 param,
403 new ArchiveImportParser()
404 );
405 }
406
407 /**
408 * Return the configuration of a project
409 *
410 * @param projectName name of the project - mandatory
411 *
412 * @return a {@link ProjectConfig} instance - won't be null
413 *
414 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
415 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
416 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
417 * @throws IllegalArgumentException if the projectName is blank (null, empty or whitespace)
418 */
419 public ProjectConfig getProjectConfig(String projectName) throws
420 RundeckApiException, RundeckApiLoginException,
421 RundeckApiTokenException, IllegalArgumentException {
422
423 AssertUtil.notBlank(projectName, "projectName is mandatory to get the config of a project !");
424 return new ApiCall(this)
425 .get(new ApiPathBuilder("/project/", projectName, "/config"), new ProjectConfigParser("/config"));
426 }
427 /**
428 * Get a single project configuration key
429 *
430 * @param projectName name of the project - mandatory
431 * @param key name of the configuration key
432 *
433 * @return value, or null if the value is not set
434 *
435 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
436 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
437 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
438 * @throws IllegalArgumentException if the projectName is blank (null, empty or whitespace)
439 */
440 public String getProjectConfig(final String projectName, final String key) throws
441 RundeckApiException, RundeckApiLoginException,
442 RundeckApiTokenException, IllegalArgumentException {
443
444 AssertUtil.notBlank(projectName, "projectName is mandatory to get the config of a project !");
445 AssertUtil.notBlank(key, "key is mandatory to get the config key value!");
446
447 ConfigProperty configProperty = null;
448 try {
449 configProperty = new ApiCall(this)
450 .get(new ApiPathBuilder("/project/", projectName, "/config/", key),
451 new ProjectConfigPropertyParser("/property"));
452 } catch (RundeckApiException.RundeckApiHttpStatusException e) {
453 if(404==e.getStatusCode()){
454 return null;
455 }
456 throw e;
457 }
458 return configProperty.getValue();
459 }
460 /**
461 * Set a single project configuration property value
462 *
463 * @param projectName name of the project - mandatory
464 * @param key name of the configuration property
465 * @param value value of the property
466 *
467 * @return new value
468 *
469 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
470 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
471 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
472 * @throws IllegalArgumentException if the projectName is blank (null, empty or whitespace)
473 */
474 public String setProjectConfig(final String projectName, final String key, final String value) throws
475 RundeckApiException, RundeckApiLoginException,
476 RundeckApiTokenException, IllegalArgumentException {
477
478 AssertUtil.notBlank(projectName, "projectName is mandatory to set the config of a project !");
479 AssertUtil.notBlank(key, "key is mandatory to set the config key value!");
480 AssertUtil.notBlank(value, "value is mandatory to set the config key value!");
481
482 final ConfigProperty configProperty = new ApiCall(this)
483 .put(new ApiPathBuilder("/project/", projectName, "/config/", key)
484 .xml(new ProjectConfigPropertyGenerator(new ConfigProperty(key, value))),
485 new ProjectConfigPropertyParser("/property"));
486
487 return configProperty.getValue();
488 }
489 /**
490 * Set a single project configuration property value
491 *
492 * @param projectName name of the project - mandatory
493 * @param key name of the configuration property
494 *
495 * @return new value
496 *
497 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
498 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
499 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
500 * @throws IllegalArgumentException if the projectName is blank (null, empty or whitespace)
501 */
502 public void deleteProjectConfig(final String projectName, final String key) throws
503 RundeckApiException, RundeckApiLoginException,
504 RundeckApiTokenException, IllegalArgumentException {
505
506 AssertUtil.notBlank(projectName, "projectName is mandatory to set the config of a project !");
507 AssertUtil.notBlank(key, "key is mandatory to set the config key value!");
508
509 new ApiCall(this).delete(new ApiPathBuilder("/project/", projectName, "/config/",
510 key).accept("application/xml"));
511 }
512 /**
513 * Return the configuration of a project
514 *
515 * @param projectName name of the project - mandatory
516 *
517 * @return a {@link ProjectConfig} instance - won't be null
518 *
519 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
520 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
521 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
522 * @throws IllegalArgumentException if the projectName is blank (null, empty or whitespace)
523 */
524 public ProjectConfig setProjectConfig(String projectName, Map<String,String> configuration) throws
525 RundeckApiException, RundeckApiLoginException,
526 RundeckApiTokenException, IllegalArgumentException {
527
528 AssertUtil.notBlank(projectName, "projectName is mandatory to get the config of a project !");
529 return new ApiCall(this)
530 .put(new ApiPathBuilder("/project/", projectName, "/config")
531 .xml(new ProjectConfigGenerator(new ProjectConfig(configuration)))
532 , new ProjectConfigParser("/config"));
533 }
534
535 private Document projectDocument(String projectName, Map<String, String> configuration) {
536 RundeckProject project = new RundeckProject();
537 project.setName(projectName);
538 if (null != configuration) {
539 project.setProjectConfig(new ProjectConfig(configuration));
540 }
541 return new ProjectGenerator(project).generateXmlDocument();
542 }
543
544 /**
545 * Store contents to a project readme.md or motd.md
546 * @param projectName project name
547 * @param filename filename, must be readme.md or motd.md
548 * @param content content
549 */
550 public void storeProjectFile(final String projectName, final String filename, final String content){
551 AssertUtil.notBlank(projectName, "projectName is mandatory to get the file!");
552 AssertUtil.notBlank(filename, "filename is mandatory to get choose the file!");
553 AssertUtil.notBlank(content, "content is mandatory to set content!");
554 AssertUtil.inList("filename must be in the list: ", filename, "readme.md", "motd.md");
555 new ApiCall(this)
556 .put(new ApiPathBuilder("/project/", projectName, "/", filename)
557 .content( "text/plain; charset=utf-8", content)
558 .accept("text/plain"),
559 new ApiCall.PlainTextHandler()
560 );
561 }
562
563 /**
564 * Read contents of a project readme.md or motd.md if it exsts, or return null
565 * @param projectName project name
566 * @param filename filename, must be readme.md or motd.md
567 * @return contents, or null
568 */
569 public String readProjectFile(final String projectName, final String filename){
570 AssertUtil.notBlank(projectName, "projectName is mandatory to get the readme file!");
571 AssertUtil.notBlank(filename, "filename is mandatory to get choose the readme file!");
572 AssertUtil.inList("filename must be in the list: ", filename, "readme.md", "motd.md");
573 try {
574 return new ApiCall(this)
575 .get(
576 new ApiPathBuilder("/project/", projectName, "/", filename)
577 .accept("text/plain"),
578 new ApiCall.PlainTextHandler()
579 );
580 } catch (RundeckApiException.RundeckApiHttpStatusException e) {
581 if (e.getStatusCode() == 404) {
582 return null;
583 }
584 throw e;
585 }
586 }
587
588 /**
589 * Delete a project readme.md or motd.md
590 * @param projectName project name
591 * @param filename filename, must be readme.md or motd.md
592 */
593 public void deleteProjectFile(final String projectName, final String filename){
594 AssertUtil.notBlank(projectName, "projectName is mandatory to get the readme file!");
595 AssertUtil.notBlank(filename, "filename is mandatory to get choose the readme file!");
596 AssertUtil.inList("filename must be in the list: ", filename, "readme.md", "motd.md");
597 new ApiCall(this).delete(new ApiPathBuilder("/project/", projectName, "/", filename));
598 }
599 /*
600 * Jobs
601 */
602
603 /**
604 * List all jobs (for all projects)
605 *
606 * @return a {@link List} of {@link RundeckJob} : might be empty, but won't be null
607 * @throws RundeckApiException in case of error when calling the API
608 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
609 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
610 */
611 public List<RundeckJob> getJobs() throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException {
612 List<RundeckJob> jobs = new ArrayList<RundeckJob>();
613 for (RundeckProject project : getProjects()) {
614 jobs.addAll(getJobs(project.getName()));
615 }
616 return jobs;
617 }
618
619 /**
620 * List all jobs that belongs to the given project
621 *
622 * @param project name of the project - mandatory
623 * @return a {@link List} of {@link RundeckJob} : might be empty, but won't be null
624 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
625 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
626 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
627 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
628 * @see #getJobs(String, String, String, String...)
629 */
630 public List<RundeckJob> getJobs(String project) throws RundeckApiException, RundeckApiLoginException,
631 RundeckApiTokenException, IllegalArgumentException {
632 return getJobs(project, null, null, new String[0]);
633 }
634
635 /**
636 * List the jobs that belongs to the given project, and matches the given criteria (jobFilter, groupPath and jobIds)
637 *
638 * @param project name of the project - mandatory
639 * @param jobFilter a filter for the job Name - optional
640 * @param groupPath a group or partial group path to include all jobs within that group path - optional
641 * @param jobIds a list of Job IDs to include - optional
642 * @return a {@link List} of {@link RundeckJob} : might be empty, but won't be null
643 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
644 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
645 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
646 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
647 * @see #getJobs(String)
648 */
649 public List<RundeckJob> getJobs(String project, String jobFilter, String groupPath, String... jobIds)
650 throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
651 AssertUtil.notBlank(project, "project is mandatory to get all jobs !");
652 return new ApiCall(this).get(new ApiPathBuilder("/jobs").param("project", project)
653 .param("jobFilter", jobFilter)
654 .param("groupPath", groupPath)
655 .param("idlist", StringUtils.join(jobIds, ",")),
656 new ListParser<RundeckJob>(new JobParser(), "/jobs/job"));
657 }
658
659 /**
660 * Export the definitions of all jobs that belongs to the given project
661 *
662 * @param filename path of the file where the content should be saved - mandatory
663 * @param format of the export. See {@link FileType} - mandatory
664 * @param project name of the project - mandatory
665 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
666 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
667 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
668 * @throws IllegalArgumentException if the format or project is blank (null, empty or whitespace), or the format is
669 * invalid
670 * @throws IOException if we failed to write to the file
671 * @see #exportJobsToFile(String, FileType, String, String, String, String...)
672 * @see #exportJobs(String, String)
673 */
674 public void exportJobsToFile(String filename, String format, String project) throws RundeckApiException,
675 RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, IOException {
676 AssertUtil.notBlank(format, "format is mandatory to export jobs !");
677 exportJobsToFile(filename, FileType.valueOf(StringUtils.upperCase(format)), project);
678 }
679
680 /**
681 * Export the definitions of all jobs that belongs to the given project
682 *
683 * @param filename path of the file where the content should be saved - mandatory
684 * @param format of the export. See {@link FileType} - mandatory
685 * @param project name of the project - mandatory
686 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
687 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
688 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
689 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace) or the format is null
690 * @throws IOException if we failed to write to the file
691 * @see #exportJobsToFile(String, FileType, String, String, String, String...)
692 * @see #exportJobs(FileType, String)
693 */
694 public void exportJobsToFile(String filename, FileType format, String project) throws RundeckApiException,
695 RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, IOException {
696 exportJobsToFile(filename, format, project, null, null, new String[0]);
697 }
698
699 /**
700 * Export the definitions of the jobs that belongs to the given project, and matches the given criteria (jobFilter,
701 * groupPath and jobIds)
702 *
703 * @param filename path of the file where the content should be saved - mandatory
704 * @param format of the export. See {@link FileType} - mandatory
705 * @param project name of the project - mandatory
706 * @param jobFilter a filter for the job Name - optional
707 * @param groupPath a group or partial group path to include all jobs within that group path - optional
708 * @param jobIds a list of Job IDs to include - optional
709 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
710 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
711 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
712 * @throws IllegalArgumentException if the filename, format or project is blank (null, empty or whitespace), or the
713 * format is invalid
714 * @throws IOException if we failed to write to the file
715 * @see #exportJobsToFile(String, FileType, String, String, String, String...)
716 * @see #exportJobs(FileType, String, String, String, String...)
717 */
718 public void exportJobsToFile(String filename, String format, String project, String jobFilter, String groupPath,
719 String... jobIds) throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException,
720 IllegalArgumentException, IOException {
721 AssertUtil.notBlank(format, "format is mandatory to export jobs !");
722 exportJobsToFile(filename,
723 FileType.valueOf(StringUtils.upperCase(format)),
724 project,
725 jobFilter,
726 groupPath,
727 jobIds);
728 }
729
730 /**
731 * Export the definitions of the jobs that belongs to the given project, and matches the given criteria (jobFilter,
732 * groupPath and jobIds)
733 *
734 * @param filename path of the file where the content should be saved - mandatory
735 * @param format of the export. See {@link FileType} - mandatory
736 * @param project name of the project - mandatory
737 * @param jobFilter a filter for the job Name - optional
738 * @param groupPath a group or partial group path to include all jobs within that group path - optional
739 * @param jobIds a list of Job IDs to include - optional
740 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
741 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
742 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
743 * @throws IllegalArgumentException if the filename or project is blank (null, empty or whitespace), or the format
744 * is null
745 * @throws IOException if we failed to write to the file
746 * @see #exportJobs(FileType, String, String, String, String...)
747 */
748 public void exportJobsToFile(String filename, FileType format, String project, String jobFilter, String groupPath,
749 String... jobIds) throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException,
750 IllegalArgumentException, IOException {
751 AssertUtil.notBlank(filename, "filename is mandatory to export a job !");
752 InputStream inputStream = exportJobs(format, project, jobFilter, groupPath, jobIds);
753 FileUtils.writeByteArrayToFile(new File(filename), IOUtils.toByteArray(inputStream));
754 }
755
756 /**
757 * Export the definitions of all jobs that belongs to the given project
758 *
759 * @param format of the export. See {@link FileType} - mandatory
760 * @param project name of the project - mandatory
761 * @return an {@link InputStream} instance, not linked to any network resources - won't be null
762 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
763 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
764 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
765 * @throws IllegalArgumentException if the format or project is blank (null, empty or whitespace), or the format is
766 * invalid
767 * @see #exportJobs(FileType, String, String, String, String...)
768 * @see #exportJobsToFile(String, String, String)
769 */
770 public InputStream exportJobs(String format, String project) throws RundeckApiException, RundeckApiLoginException,
771 RundeckApiTokenException, IllegalArgumentException {
772 AssertUtil.notBlank(format, "format is mandatory to export jobs !");
773 return exportJobs(FileType.valueOf(StringUtils.upperCase(format)), project);
774 }
775
776 /**
777 * Export the definitions of all jobs that belongs to the given project
778 *
779 * @param format of the export. See {@link FileType} - mandatory
780 * @param project name of the project - mandatory
781 * @return an {@link InputStream} instance, not linked to any network resources - won't be null
782 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
783 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
784 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
785 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace) or the format is null
786 * @see #exportJobs(FileType, String, String, String, String...)
787 * @see #exportJobsToFile(String, FileType, String)
788 */
789 public InputStream exportJobs(FileType format, String project) throws RundeckApiException,
790 RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
791 return exportJobs(format, project, null, null, new String[0]);
792 }
793
794 /**
795 * Export the definitions of the jobs that belongs to the given project, and matches the given criteria (jobFilter,
796 * groupPath and jobIds)
797 *
798 * @param format of the export. See {@link FileType} - mandatory
799 * @param project name of the project - mandatory
800 * @param jobFilter a filter for the job Name - optional
801 * @param groupPath a group or partial group path to include all jobs within that group path - optional
802 * @param jobIds a list of Job IDs to include - optional
803 * @return an {@link InputStream} instance, not linked to any network resources - won't be null
804 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
805 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
806 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
807 * @throws IllegalArgumentException if the format or project is blank (null, empty or whitespace), or the format is
808 * invalid
809 * @see #exportJobs(FileType, String, String, String, String...)
810 * @see #exportJobsToFile(String, String, String, String, String, String...)
811 */
812 public InputStream exportJobs(String format, String project, String jobFilter, String groupPath, String... jobIds)
813 throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
814 AssertUtil.notBlank(format, "format is mandatory to export jobs !");
815 return exportJobs(FileType.valueOf(StringUtils.upperCase(format)), project, jobFilter, groupPath, jobIds);
816 }
817
818 /**
819 * Export the definitions of the jobs that belongs to the given project, and matches the given criteria (jobFilter,
820 * groupPath and jobIds)
821 *
822 * @param format of the export. See {@link FileType} - mandatory
823 * @param project name of the project - mandatory
824 * @param jobFilter a filter for the job Name - optional
825 * @param groupPath a group or partial group path to include all jobs within that group path - optional
826 * @param jobIds a list of Job IDs to include - optional
827 * @return an {@link InputStream} instance, not linked to any network resources - won't be null
828 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
829 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
830 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
831 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace) or the format is null
832 * @see #exportJobsToFile(String, FileType, String, String, String, String...)
833 */
834 public InputStream exportJobs(FileType format, String project, String jobFilter, String groupPath, String... jobIds)
835 throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
836 AssertUtil.notNull(format, "format is mandatory to export jobs !");
837 AssertUtil.notBlank(project, "project is mandatory to export jobs !");
838 return new ApiCall(this).get(new ApiPathBuilder("/jobs/export")
839 .accept(format == FileType.XML ? "text/xml" : "text/yaml")
840 .param("format", format)
841 .param("project", project)
842 .param("jobFilter", jobFilter)
843 .param("groupPath", groupPath)
844 .param("idlist", StringUtils.join(jobIds, ",")),false);
845 }
846
847 /**
848 * Export the definition of a single job (identified by the given ID)
849 *
850 * @param filename path of the file where the content should be saved - mandatory
851 * @param format of the export. See {@link FileType} - mandatory
852 * @param jobId identifier of the job - mandatory
853 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
854 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
855 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
856 * @throws IllegalArgumentException if the filename, format or jobId is blank (null, empty or whitespace), or the
857 * format is invalid
858 * @throws IOException if we failed to write to the file
859 * @see #exportJobToFile(String, FileType, String)
860 * @see #exportJob(String, String)
861 * @see #getJob(String)
862 */
863 public void exportJobToFile(String filename, String format, String jobId) throws RundeckApiException,
864 RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, IOException {
865 AssertUtil.notBlank(format, "format is mandatory to export a job !");
866 exportJobToFile(filename, FileType.valueOf(StringUtils.upperCase(format)), jobId);
867 }
868
869 /**
870 * Export the definition of a single job (identified by the given ID)
871 *
872 * @param filename path of the file where the content should be saved - mandatory
873 * @param format of the export. See {@link FileType} - mandatory
874 * @param jobId identifier of the job - mandatory
875 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
876 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
877 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
878 * @throws IllegalArgumentException if the filename or jobId is blank (null, empty or whitespace), or the format is
879 * null
880 * @throws IOException if we failed to write to the file
881 * @see #exportJob(FileType, String)
882 * @see #getJob(String)
883 */
884 public void exportJobToFile(String filename, FileType format, String jobId) throws RundeckApiException,
885 RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, IOException {
886 AssertUtil.notBlank(filename, "filename is mandatory to export a job !");
887 InputStream inputStream = exportJob(format, jobId);
888 FileUtils.writeByteArrayToFile(new File(filename), IOUtils.toByteArray(inputStream));
889 }
890
891 /**
892 * Export the definition of a single job, identified by the given ID
893 *
894 * @param format of the export. See {@link FileType} - mandatory
895 * @param jobId identifier of the job - mandatory
896 * @return an {@link InputStream} instance, not linked to any network resources - won't be null
897 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
898 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
899 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
900 * @throws IllegalArgumentException if the format or jobId is blank (null, empty or whitespace), or the format is
901 * invalid
902 * @see #exportJobToFile(String, String, String)
903 * @see #getJob(String)
904 */
905 public InputStream exportJob(String format, String jobId) throws RundeckApiException, RundeckApiLoginException,
906 RundeckApiTokenException, IllegalArgumentException {
907 AssertUtil.notBlank(format, "format is mandatory to export a job !");
908 return exportJob(FileType.valueOf(StringUtils.upperCase(format)), jobId);
909 }
910
911 /**
912 * Export the definition of a single job, identified by the given ID
913 *
914 * @param format of the export. See {@link FileType} - mandatory
915 * @param jobId identifier of the job - mandatory
916 * @return an {@link InputStream} instance, not linked to any network resources - won't be null
917 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
918 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
919 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
920 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace), or the format is null
921 * @see #exportJobToFile(String, FileType, String)
922 * @see #getJob(String)
923 */
924 public InputStream exportJob(FileType format, String jobId) throws RundeckApiException, RundeckApiLoginException,
925 RundeckApiTokenException, IllegalArgumentException {
926 AssertUtil.notNull(format, "format is mandatory to export a job !");
927 AssertUtil.notBlank(jobId, "jobId is mandatory to export a job !");
928 return new ApiCall(this).get(new ApiPathBuilder("/job/", jobId).param("format", format), false);
929 }
930
931
932 /**
933 * Import the definitions of jobs, from the given input stream, using the given behavior
934 *
935 * @param rundeckJobsImport import request, see {@link RundeckJobsImportBuilder}
936 *
937 * @return a {@link RundeckJobsImportResult} instance - won't be null
938 *
939 * @throws RundeckApiException in case of error when calling the API
940 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
941 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
942 * @throws IllegalArgumentException if the stream or fileType is null
943 * @see #importJobs(RundeckJobsImport)
944 */
945 public RundeckJobsImportResult importJobs(final String filename,final RundeckJobsImport rundeckJobsImport) throws RundeckApiException,
946 RundeckApiLoginException,
947 RundeckApiTokenException, IllegalArgumentException, IOException {
948 AssertUtil.notBlank(filename, "filename (of jobs file) is mandatory to import jobs !");
949 FileInputStream stream = null;
950 try {
951 stream = FileUtils.openInputStream(new File(filename));
952 return importJobs(RundeckJobsImportBuilder.builder(rundeckJobsImport).setStream(stream).build());
953 } finally {
954
955 IOUtils.closeQuietly(stream);
956 }
957 }
958 /**
959 * Import the definitions of jobs, from the given input stream, using the given behavior
960 *
961 * @param rundeckJobsImport import request, see {@link RundeckJobsImportBuilder}
962 *
963 * @return a {@link RundeckJobsImportResult} instance - won't be null
964 *
965 * @throws RundeckApiException in case of error when calling the API
966 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
967 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
968 * @throws IllegalArgumentException if the stream or fileType is null
969 * @see #importJobs(String, RundeckJobsImport)
970 */
971 public RundeckJobsImportResult importJobs(final RundeckJobsImport rundeckJobsImport) throws RundeckApiException,
972 RundeckApiLoginException,
973 RundeckApiTokenException, IllegalArgumentException {
974
975 AssertUtil.notNull(rundeckJobsImport.getStream(), "inputStream of jobs is mandatory to import jobs !");
976 AssertUtil.notNull(rundeckJobsImport.getFileType(), "fileType is mandatory to import jobs !");
977 final ApiPathBuilder request = new ApiPathBuilder(JOBS_IMPORT)
978 .param("format", rundeckJobsImport.getFileType())
979 .param("dupeOption", rundeckJobsImport.getImportMethod())
980 .attach("xmlBatch", rundeckJobsImport.getStream());
981 if(null!=rundeckJobsImport.getUuidImportBehavior()) {
982 //API v9
983 request.param("uuidOption", rundeckJobsImport.getUuidImportBehavior());
984 }
985 if(null!=rundeckJobsImport.getProject()) {
986 //API v8
987 request.param("project", rundeckJobsImport.getProject());
988 }
989 return new ApiCall(this).post(request, new JobsImportResultParser("result"));
990 }
991
992 /**
993 * Find a job, identified by its project, group and name. Note that the groupPath is optional, as a job does not
994 * need to belong to a group (either pass null, or an empty string).
995 *
996 * @param project name of the project - mandatory
997 * @param groupPath group to which the job belongs (if it belongs to a group) - optional
998 * @param name of the job to find - mandatory
999 * @return a {@link RundeckJob} instance - null if not found
1000 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
1001 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1002 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1003 * @throws IllegalArgumentException if the project or the name is blank (null, empty or whitespace)
1004 * @see #getJob(String)
1005 */
1006 public RundeckJob findJob(String project, String groupPath, String name) throws RundeckApiException,
1007 RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
1008 AssertUtil.notBlank(project, "project is mandatory to find a job !");
1009 AssertUtil.notBlank(name, "job name is mandatory to find a job !");
1010 List<RundeckJob> jobs = getJobs(project, name, groupPath, new String[0]);
1011 return jobs.isEmpty() ? null : jobs.get(0);
1012 }
1013
1014 /**
1015 * Get the definition of a single job, identified by the given ID
1016 *
1017 * @param jobId identifier of the job - mandatory
1018 * @return a {@link RundeckJob} instance - won't be null
1019 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
1020 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1021 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1022 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
1023 * @see #findJob(String, String, String)
1024 * @see #exportJob(String, String)
1025 */
1026 public RundeckJob getJob(String jobId) throws RundeckApiException, RundeckApiLoginException,
1027 RundeckApiTokenException, IllegalArgumentException {
1028 AssertUtil.notBlank(jobId, "jobId is mandatory to get the details of a job !");
1029 return new ApiCall(this).get(new ApiPathBuilder("/job/", jobId), new JobParser("joblist/job"));
1030 }
1031
1032 /**
1033 * Delete a single job, identified by the given ID
1034 *
1035 * @param jobId identifier of the job - mandatory
1036 * @return the success message (note that in case of error, you'll get an exception)
1037 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
1038 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1039 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1040 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
1041 */
1042 public String deleteJob(String jobId) throws RundeckApiException, RundeckApiLoginException,
1043 RundeckApiTokenException, IllegalArgumentException {
1044 AssertUtil.notBlank(jobId, "jobId is mandatory to delete a job !");
1045 new ApiCall(this).delete(new ApiPathBuilder("/job/", jobId));
1046 return "Job " + jobId + " was deleted successfully";
1047 }
1048 /**
1049 * Delete multiple jobs, identified by the given IDs
1050 *
1051 * @param jobIds List of job IDS
1052 * @return the bulk delete result
1053 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
1054 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1055 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1056 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
1057 */
1058 public RundeckJobDeleteBulk deleteJobs(final List<String> jobIds) throws RundeckApiException, RundeckApiLoginException,
1059 RundeckApiTokenException, IllegalArgumentException {
1060 if (null == jobIds || 0 == jobIds.size()) {
1061 throw new IllegalArgumentException("jobIds are mandatory to delete a job");
1062 }
1063 return new ApiCall(this).post(new ApiPathBuilder("/jobs/delete").field("ids",jobIds),
1064 new BulkDeleteParser("/deleteJobs"));
1065 }
1066
1067 /**
1068 * Trigger the execution of a Rundeck job (identified by the given ID), and return immediately (without waiting the
1069 * end of the job execution)
1070 *
1071 * @param jobRun the RunJob, see {@link RunJobBuilder}
1072 * @return a {@link RundeckExecution} instance for the newly created (and running) execution - won't be null
1073 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
1074 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1075 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1076 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
1077 * @see #runJob(RunJob)
1078 */
1079 public RundeckExecution triggerJob(final RunJob jobRun)
1080 throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
1081 AssertUtil.notBlank(jobRun.getJobId(), "jobId is mandatory to trigger a job !");
1082 ApiPathBuilder apiPath = new ApiPathBuilder("/job/", jobRun.getJobId(), "/run").param("argString",
1083 ParametersUtil.generateArgString(jobRun.getOptions()))
1084 .nodeFilters(jobRun.getNodeFilters());
1085 if(null!=jobRun.getAsUser()) {
1086 apiPath.param("asUser", jobRun.getAsUser());
1087 }
1088 return new ApiCall(this).get(
1089 apiPath,
1090 new ExecutionParser(
1091 "/executions/execution"
1092 )
1093
1094 );
1095 }
1096
1097
1098 /**
1099 * Run a Rundeck job (identified by the given ID), and wait until its execution is finished (or aborted) to return.
1100 * We will poll the Rundeck server at regular interval (every 5 seconds) to know if the execution is finished (or
1101 * aborted) or is still running.
1102 *
1103 * @param runJob the RunJob, see {@link RunJobBuilder}
1104 *
1105 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
1106 *
1107 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
1108 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1109 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1110 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
1111 * @see #triggerJob(RunJob)
1112 * @see #runJob(RunJob, long, TimeUnit)
1113 */
1114 public RundeckExecution runJob(final RunJob runJob) throws RundeckApiException, RundeckApiLoginException,
1115 RundeckApiTokenException, IllegalArgumentException {
1116 return runJob(runJob, DEFAULT_POOLING_INTERVAL, DEFAULT_POOLING_UNIT);
1117 }
1118
1119 /**
1120 * Run a Rundeck job (identified by the given ID), and wait until its execution is finished (or aborted) to return.
1121 * We will poll the Rundeck server at regular interval (configured by the poolingInterval/poolingUnit couple) to
1122 * know if the execution is finished (or aborted) or is still running.
1123 *
1124 * @param jobRun the RunJob, see {@link RunJobBuilder}
1125 * @param poolingInterval for checking the status of the execution. Must be > 0.
1126 * @param poolingUnit unit (seconds, milli-seconds, ...) of the interval. Default to seconds.
1127 *
1128 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
1129 *
1130 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
1131 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1132 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1133 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
1134 * @see #triggerJob(RunJob)
1135 */
1136 public RundeckExecution runJob(final RunJob jobRun, long poolingInterval,
1137 TimeUnit poolingUnit) throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException,
1138 IllegalArgumentException {
1139
1140 if (poolingInterval <= 0) {
1141 poolingInterval = DEFAULT_POOLING_INTERVAL;
1142 poolingUnit = DEFAULT_POOLING_UNIT;
1143 }
1144 if (poolingUnit == null) {
1145 poolingUnit = DEFAULT_POOLING_UNIT;
1146 }
1147
1148 RundeckExecution execution = triggerJob(jobRun);
1149 while (ExecutionStatus.RUNNING.equals(execution.getStatus())) {
1150 try {
1151 Thread.sleep(poolingUnit.toMillis(poolingInterval));
1152 } catch (InterruptedException e) {
1153 break;
1154 }
1155 execution = getExecution(execution.getId());
1156 }
1157 return execution;
1158 }
1159
1160 /*
1161 * Ad-hoc commands
1162 */
1163
1164
1165 /**
1166 * Trigger the execution of an ad-hoc command, and return immediately (without waiting the end of the execution).
1167 * The command will be dispatched to nodes, accordingly to the nodeFilters parameter.
1168 *
1169 * @param command the RunAdhocCommand. Project and command are mandatory, see {@link RunAdhocCommandBuilder}
1170 * @return a {@link RundeckExecution} instance for the newly created (and running) execution - won't be null
1171 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
1172 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1173 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1174 * @throws IllegalArgumentException if the project or command is blank (null, empty or whitespace)
1175 * @see #runAdhocCommand(RunAdhocCommand)
1176 */
1177 public RundeckExecution triggerAdhocCommand(RunAdhocCommand command) throws RundeckApiException, RundeckApiLoginException,
1178 RundeckApiTokenException, IllegalArgumentException {
1179 AssertUtil.notBlank(command.getProject(), "project is mandatory to trigger an ad-hoc command !");
1180 AssertUtil.notBlank(command.getCommand(), "command is mandatory to trigger an ad-hoc command !");
1181 ApiPathBuilder apiPath = new ApiPathBuilder("/run/command").param("project", command.getProject())
1182 .param("exec", command.getCommand())
1183 .param("nodeThreadcount",
1184 command.getNodeThreadcount())
1185 .param("nodeKeepgoing",
1186 command.getNodeKeepgoing())
1187 .nodeFilters(command.getNodeFilters());
1188 if(null!= command.getAsUser()) {
1189 apiPath.param("asUser", command.getAsUser());
1190 }
1191 RundeckExecution execution = new ApiCall(this).get(apiPath, new ExecutionParser("/execution"));
1192 // the first call just returns the ID of the execution, so we need another call to get a "real" execution
1193 return getExecution(execution.getId());
1194 }
1195
1196
1197 /**
1198 * Run an ad-hoc command, and wait until its execution is finished (or aborted) to return. We will poll the Rundeck
1199 * server at regular interval (every 5 seconds) to know if the execution is finished (or aborted) or is still
1200 * running. The command will be dispatched to nodes, accordingly to the nodeFilters parameter.
1201 *
1202 * @param command the RunAdhocCommand, see {@link RunAdhocCommandBuilder}
1203 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
1204 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
1205 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1206 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1207 * @throws IllegalArgumentException if the project or command is blank (null, empty or whitespace)
1208 * @see #runAdhocCommand(RunAdhocCommand, long, TimeUnit)
1209 * @see #triggerAdhocCommand(RunAdhocCommand)
1210 */
1211 public RundeckExecution runAdhocCommand(RunAdhocCommand command) throws RundeckApiException, RundeckApiLoginException,
1212 RundeckApiTokenException, IllegalArgumentException {
1213 return runAdhocCommand(command,
1214 DEFAULT_POOLING_INTERVAL,
1215 DEFAULT_POOLING_UNIT);
1216 }
1217
1218 /**
1219 * Run an ad-hoc command, and wait until its execution is finished (or aborted) to return. We will poll the Rundeck
1220 * server at regular interval (configured by the poolingInterval/poolingUnit couple) to know if the execution is
1221 * finished (or aborted) or is still running. The command will be dispatched to nodes, accordingly to the
1222 * nodeFilters parameter.
1223 *
1224 * @param command the RunAdhocCommand, see {@link RunAdhocCommandBuilder}
1225 * @param poolingInterval for checking the status of the execution. Must be > 0.
1226 * @param poolingUnit unit (seconds, milli-seconds, ...) of the interval. Default to seconds.
1227 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
1228 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
1229 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1230 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1231 * @throws IllegalArgumentException if the project or command is blank (null, empty or whitespace)
1232 * @see #triggerAdhocCommand(RunAdhocCommand)
1233 */
1234 public RundeckExecution runAdhocCommand(RunAdhocCommand command, long poolingInterval, TimeUnit poolingUnit)
1235 throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
1236 if (poolingInterval <= 0) {
1237 poolingInterval = DEFAULT_POOLING_INTERVAL;
1238 poolingUnit = DEFAULT_POOLING_UNIT;
1239 }
1240 if (poolingUnit == null) {
1241 poolingUnit = DEFAULT_POOLING_UNIT;
1242 }
1243
1244 RundeckExecution execution = triggerAdhocCommand(command);
1245 while (ExecutionStatus.RUNNING.equals(execution.getStatus())) {
1246 try {
1247 Thread.sleep(poolingUnit.toMillis(poolingInterval));
1248 } catch (InterruptedException e) {
1249 break;
1250 }
1251 execution = getExecution(execution.getId());
1252 }
1253 return execution;
1254 }
1255
1256 /*
1257 * Ad-hoc scripts
1258 */
1259
1260
1261 /**
1262 * Trigger the execution of an ad-hoc script read from a file, and return immediately (without waiting the end of
1263 * the execution). The script will be dispatched to nodes, accordingly to the nodeFilters parameter.
1264 *
1265 * @param script the RunAdhocScript, see {@link RunAdhocScriptBuilder}
1266 * @param scriptFilename a file to read as the input script stream
1267 *
1268 * @return a {@link RundeckExecution} instance for the newly created (and running) execution - won't be null
1269 *
1270 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
1271 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1272 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1273 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace) or the script is null
1274 * @throws IOException if an error occurs reading the script file
1275 * @see #triggerAdhocScript(RunAdhocScript)
1276 * @see #runAdhocScript(RunAdhocScript, long, java.util.concurrent.TimeUnit)
1277 */
1278 public RundeckExecution triggerAdhocScript(final RunAdhocScript script, final String scriptFilename) throws
1279 RundeckApiException,
1280 RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, IOException {
1281 AssertUtil.notBlank(scriptFilename, "scriptFilename is mandatory to trigger an ad-hoc script !");
1282 FileInputStream stream = null;
1283 try {
1284 stream = FileUtils.openInputStream(new File(scriptFilename));
1285 return triggerAdhocScript(RunAdhocScriptBuilder.builder(script)
1286 .setScript(stream)
1287 .build());
1288 } finally {
1289 IOUtils.closeQuietly(stream);
1290 }
1291 }
1292 /**
1293 * Trigger the execution of an ad-hoc script, and return immediately (without waiting the end of the execution). The
1294 * script will be dispatched to nodes, accordingly to the nodeFilters parameter.
1295 *
1296 * @param script the RunAdhocScript, see {@link RunAdhocScriptBuilder}
1297 * @return a {@link RundeckExecution} instance for the newly created (and running) execution - won't be null
1298 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
1299 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1300 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1301 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace) or the script is null
1302 * @see #triggerAdhocScript(RunAdhocScript, String)
1303 * @see #runAdhocScript(RunAdhocScript)
1304 */
1305 public RundeckExecution triggerAdhocScript(RunAdhocScript script) throws RundeckApiException,
1306 RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
1307 AssertUtil.notBlank(script.getProject(), "project is mandatory to trigger an ad-hoc script !");
1308 AssertUtil.notNull(script.getScript(), "script is mandatory to trigger an ad-hoc script !");
1309 ApiPathBuilder apiPath = new ApiPathBuilder("/run/script").param("project", script.getProject())
1310 .attach("scriptFile",
1311 script.getScript())
1312 .param("argString",script.getArgString())
1313 .param("nodeThreadcount",
1314 script.getNodeThreadcount())
1315 .param("nodeKeepgoing",
1316 script.getNodeKeepgoing())
1317 .param("scriptInterpreter",
1318 script.getScriptInterpreter())
1319 .param("interpreterArgsQuoted",
1320 script.getInterpreterArgsQuoted())
1321 .nodeFilters(script.getNodeFilters());
1322 if(null!=script.getAsUser()) {
1323 apiPath.param("asUser", script.getAsUser());
1324 }
1325 RundeckExecution execution = new ApiCall(this).post(apiPath, new ExecutionParser("/execution"));
1326 // the first call just returns the ID of the execution, so we need another call to get a "real" execution
1327 return getExecution(execution.getId());
1328 }
1329
1330
1331 /**
1332 * Run an ad-hoc script, and wait until its execution is finished (or aborted) to return. We will poll the Rundeck
1333 * server at regular interval (every 5 seconds) to know if the execution is finished (or aborted) or is still
1334 * running. The script will be dispatched to nodes, accordingly to the nodeFilters parameter.
1335 *
1336 * @param script the RunAdhocScript, see {@link RunAdhocScriptBuilder}
1337 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
1338 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
1339 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1340 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1341 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace) or the script is null
1342 * @throws IOException if we failed to read the file
1343 * @see #runAdhocScript(RunAdhocScript, long, java.util.concurrent.TimeUnit)
1344 * @see #triggerAdhocScript(RunAdhocScript)
1345 */
1346 public RundeckExecution runAdhocScript(RunAdhocScript script) throws RundeckApiException,
1347 RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException, IOException {
1348 return runAdhocScript(script,
1349 DEFAULT_POOLING_INTERVAL,
1350 DEFAULT_POOLING_UNIT);
1351 }
1352
1353 /**
1354 * Run an ad-hoc script read from a file, and wait until its execution is finished (or aborted) to return. We will
1355 * poll the Rundeck server at regular interval (configured by the poolingInterval/poolingUnit couple) to know if the
1356 * execution is finished (or aborted) or is still running. The script will be dispatched to nodes, accordingly to
1357 * the nodeFilters parameter.
1358 *
1359 * @param script the RunAdhocScript, see {@link RunAdhocScriptBuilder}
1360 * @param scriptFilename filename of a script to read
1361 * @param poolingInterval for checking the status of the execution. Must be > 0.
1362 * @param poolingUnit unit (seconds, milli-seconds, ...) of the interval. Default to seconds.
1363 *
1364 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
1365 *
1366 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
1367 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1368 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1369 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace) or the script is null
1370 * @throws IOException if we failed to read the file
1371 * @see #runAdhocScript(RunAdhocScript)
1372 * @see #triggerAdhocScript(RunAdhocScript, String)
1373 */
1374 public RundeckExecution runAdhocScript(final RunAdhocScript script, final String scriptFilename,
1375 final long poolingInterval, final TimeUnit poolingUnit) throws RundeckApiException,
1376 RundeckApiLoginException, RundeckApiTokenException,
1377 IllegalArgumentException, IOException {
1378 FileInputStream stream = null;
1379 try {
1380 stream = FileUtils.openInputStream(new File(scriptFilename));
1381 return runAdhocScript(RunAdhocScriptBuilder.builder(script)
1382 .setScript(stream)
1383 .build(), poolingInterval, poolingUnit);
1384 } finally {
1385 IOUtils.closeQuietly(stream);
1386 }
1387 }
1388 /**
1389 * Run an ad-hoc script, and wait until its execution is finished (or aborted) to return. We will poll the Rundeck
1390 * server at regular interval (configured by the poolingInterval/poolingUnit couple) to know if the execution is
1391 * finished (or aborted) or is still running. The script will be dispatched to nodes, accordingly to the nodeFilters
1392 * parameter.
1393 *
1394 * @param script the RunAdhocScript, see {@link RunAdhocScriptBuilder}
1395 * @param poolingInterval for checking the status of the execution. Must be > 0.
1396 * @param poolingUnit unit (seconds, milli-seconds, ...) of the interval. Default to seconds.
1397 * @return a {@link RundeckExecution} instance for the (finished/aborted) execution - won't be null
1398 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
1399 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1400 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1401 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace) or the script is null
1402 * @throws IOException if we failed to read the file
1403 * @see #runAdhocScript(RunAdhocScript, long, TimeUnit)
1404 * @see #triggerAdhocScript(RunAdhocScript)
1405 */
1406 public RundeckExecution runAdhocScript(final RunAdhocScript script, long poolingInterval,
1407 TimeUnit poolingUnit) throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException,
1408 IllegalArgumentException {
1409 if (poolingInterval <= 0) {
1410 poolingInterval = DEFAULT_POOLING_INTERVAL;
1411 poolingUnit = DEFAULT_POOLING_UNIT;
1412 }
1413 if (poolingUnit == null) {
1414 poolingUnit = DEFAULT_POOLING_UNIT;
1415 }
1416
1417 RundeckExecution execution = triggerAdhocScript(script);
1418 while (ExecutionStatus.RUNNING.equals(execution.getStatus())) {
1419 try {
1420 Thread.sleep(poolingUnit.toMillis(poolingInterval));
1421 } catch (InterruptedException e) {
1422 break;
1423 }
1424 execution = getExecution(execution.getId());
1425 }
1426 return execution;
1427 }
1428
1429 /*
1430 * Executions
1431 */
1432
1433 /**
1434 * Get all running executions (for all projects)
1435 *
1436 * @return a {@link List} of {@link RundeckExecution} : might be empty, but won't be null
1437 * @throws RundeckApiException in case of error when calling the API
1438 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1439 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1440 * @see #getRunningExecutions(String)
1441 */
1442 public List<RundeckExecution> getRunningExecutions() throws RundeckApiException, RundeckApiLoginException,
1443 RundeckApiTokenException {
1444 if (this.getApiVersion() >= Version.V9.getVersionNumber()) {
1445 //simply query using '*'
1446 return getRunningExecutions("*");
1447 } else {
1448 List<RundeckExecution> executions = new ArrayList<RundeckExecution>();
1449 for (RundeckProject project : getProjects()) {
1450 executions.addAll(getRunningExecutions(project.getName()));
1451 }
1452 return executions;
1453 }
1454 }
1455
1456 /**
1457 * Get the running executions for the given project
1458 *
1459 * @param project name of the project - mandatory
1460 * @return a {@link List} of {@link RundeckExecution} : might be empty, but won't be null
1461 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
1462 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1463 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1464 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
1465 * @see #getRunningExecutions()
1466 */
1467 public List<RundeckExecution> getRunningExecutions(String project) throws RundeckApiException,
1468 RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
1469 AssertUtil.notBlank(project, "project is mandatory get all running executions !");
1470 return new ApiCall(this).get(new ApiPathBuilder("/executions/running").param("project", project),
1471 new ListParser<>(
1472 new ExecutionParser(),
1473 "/executions/execution"
1474 ));
1475 }
1476
1477 /**
1478 * Get the executions of the given job
1479 *
1480 * @param jobId identifier of the job - mandatory
1481 * @return a {@link List} of {@link RundeckExecution} : might be empty, but won't be null
1482 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
1483 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1484 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1485 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
1486 * @see #getJobExecutions(String, RundeckExecution.ExecutionStatus, Long, Long)
1487 */
1488 public List<RundeckExecution> getJobExecutions(String jobId) throws RundeckApiException, RundeckApiLoginException,
1489 RundeckApiTokenException, IllegalArgumentException {
1490 return getJobExecutions(jobId, (ExecutionStatus) null);
1491 }
1492
1493 /**
1494 * Get the executions of the given job
1495 *
1496 * @param jobId identifier of the job - mandatory
1497 * @param status of the executions, see {@link ExecutionStatus} - optional (null for all)
1498 * @return a {@link List} of {@link RundeckExecution} : might be empty, but won't be null
1499 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
1500 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1501 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1502 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace), or the executionStatus is
1503 * invalid
1504 * @see #getJobExecutions(String, String, Long, Long)
1505 */
1506 public List<RundeckExecution> getJobExecutions(String jobId, String status) throws RundeckApiException,
1507 RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
1508 return getJobExecutions(jobId,
1509 StringUtils.isBlank(status) ? null : ExecutionStatus.valueOf(StringUtils.upperCase(status)));
1510 }
1511
1512 /**
1513 * Get the executions of the given job
1514 *
1515 * @param jobId identifier of the job - mandatory
1516 * @param status of the executions, see {@link ExecutionStatus} - optional (null for all)
1517 * @return a {@link List} of {@link RundeckExecution} : might be empty, but won't be null
1518 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
1519 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1520 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1521 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
1522 * @see #getJobExecutions(String, RundeckExecution.ExecutionStatus, Long, Long)
1523 */
1524 public List<RundeckExecution> getJobExecutions(String jobId, ExecutionStatus status) throws RundeckApiException,
1525 RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
1526 return getJobExecutions(jobId, status, null, null);
1527 }
1528
1529 /**
1530 * Get the executions of the given job
1531 *
1532 * @param jobId identifier of the job - mandatory
1533 * @param status of the executions, see {@link ExecutionStatus} - optional (null for all)
1534 * @param max number of results to return - optional (null for all)
1535 * @param offset the 0-indexed offset for the first result to return - optional
1536 * @return a {@link List} of {@link RundeckExecution} : might be empty, but won't be null
1537 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
1538 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1539 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1540 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace), or the executionStatus is
1541 * invalid
1542 * @see #getJobExecutions(String, RundeckExecution.ExecutionStatus, Long, Long)
1543 */
1544 public List<RundeckExecution> getJobExecutions(String jobId, String status, Long max, Long offset)
1545 throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
1546 return getJobExecutions(jobId,
1547 StringUtils.isBlank(status) ? null : ExecutionStatus.valueOf(StringUtils.upperCase(status)),
1548 max,
1549 offset);
1550 }
1551
1552 /**
1553 * Get the executions of the given job
1554 *
1555 * @param jobId identifier of the job - mandatory
1556 * @param status of the executions, see {@link ExecutionStatus} - optional (null for all)
1557 * @param max number of results to return - optional (null for all)
1558 * @param offset the 0-indexed offset for the first result to return - optional
1559 * @return a {@link List} of {@link RundeckExecution} : might be empty, but won't be null
1560 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
1561 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1562 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1563 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
1564 */
1565 public List<RundeckExecution> getJobExecutions(String jobId, ExecutionStatus status, Long max, Long offset)
1566 throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
1567 AssertUtil.notBlank(jobId, "jobId is mandatory to get the executions of a job !");
1568 return new ApiCall(this).get(new ApiPathBuilder("/job/", jobId, "/executions").param("status", status)
1569 .param("max", max)
1570 .param("offset", offset),
1571 new ListParser<RundeckExecution>(new ExecutionParser(),
1572 "/executions/execution"));
1573 }
1574
1575 /**
1576 * Get executions based on query parameters
1577 *
1578 * @param query query parameters for the request
1579 * @param max number of results to return - optional (null for all)
1580 * @param offset the 0-indexed offset for the first result to return - optional
1581 * @return a {@link List} of {@link RundeckExecution} : might be empty, but won't be null
1582 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
1583 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1584 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1585 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
1586 */
1587 public PagedResults<RundeckExecution> getExecutions(ExecutionQuery query, Long max, Long offset)
1588 throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
1589 if (!query.notBlank()) {
1590 throw new IllegalArgumentException("Some execution query parameter must be set");
1591 }
1592 AssertUtil.notBlank(query.getProject(), "project is required for execution query");
1593 return new ApiCall(this).get(
1594 new ApiPathBuilder("/executions")
1595 .param(new ExecutionQueryParameters(query))
1596 .param("max", max)
1597 .param("offset", offset),
1598 new PagedResultParser<>(new ListParser<>(new ExecutionParser(), "execution"), "/executions")
1599 );
1600 }
1601
1602 /**
1603 * Get a single execution, identified by the given ID
1604 *
1605 * @param executionId identifier of the execution - mandatory
1606 * @return a {@link RundeckExecution} instance - won't be null
1607 * @throws RundeckApiException in case of error when calling the API (non-existent execution with this ID)
1608 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1609 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1610 * @throws IllegalArgumentException if the executionId is null
1611 */
1612 public RundeckExecution getExecution(Long executionId) throws RundeckApiException, RundeckApiLoginException,
1613 RundeckApiTokenException, IllegalArgumentException {
1614 AssertUtil.notNull(executionId, "executionId is mandatory to get the details of an execution !");
1615 return new ApiCall(this).get(
1616 new ApiPathBuilder("/execution/", executionId.toString()),
1617 new ExecutionParser("/executions/execution")
1618 );
1619 }
1620
1621 /**
1622 * Abort an execution (identified by the given ID). The execution should be running...
1623 *
1624 * @param executionId identifier of the execution - mandatory
1625 * @return a {@link RundeckAbort} instance - won't be null
1626 * @throws RundeckApiException in case of error when calling the API (non-existent execution with this ID)
1627 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1628 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1629 * @throws IllegalArgumentException if the executionId is null
1630 */
1631 public RundeckAbort abortExecution(Long executionId) throws RundeckApiException, RundeckApiLoginException,
1632 RundeckApiTokenException, IllegalArgumentException {
1633 return abortExecution(executionId, null);
1634 }
1635 /**
1636 * Abort an execution (identified by the given ID). The execution should be running...
1637 *
1638 * @param executionId identifier of the execution - mandatory
1639 * @param asUser specify a user name to abort the job as, must have 'killAs' permission
1640 * @return a {@link RundeckAbort} instance - won't be null
1641 * @throws RundeckApiException in case of error when calling the API (non-existent execution with this ID)
1642 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1643 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1644 * @throws IllegalArgumentException if the executionId is null
1645 */
1646 public RundeckAbort abortExecution(Long executionId, final String asUser) throws RundeckApiException, RundeckApiLoginException,
1647 RundeckApiTokenException, IllegalArgumentException {
1648 AssertUtil.notNull(executionId, "executionId is mandatory to abort an execution !");
1649 ApiPathBuilder apiPath = new ApiPathBuilder("/execution/", executionId.toString(), "/abort");
1650 if(null!=asUser) {
1651 apiPath.param("asUser", asUser);
1652 }
1653 return new ApiCall(this).get(apiPath, new AbortParser( "/abort"));
1654 }
1655
1656 /**
1657 * Delete all executions for a job specified by a job ID
1658 *
1659 * @param jobId Identifier for the job
1660 *
1661 * @return a {@link DeleteExecutionsResponse} instance - won't be null
1662 *
1663 * @throws RundeckApiException in case of error when calling the API (non-existent
1664 * execution with this ID)
1665 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1666 * @throws RundeckApiTokenException if the token is invalid (in case of token-based
1667 * authentication)
1668 * @throws IllegalArgumentException if the executionIds is null
1669 */
1670 public DeleteExecutionsResponse deleteAllJobExecutions(final String jobId)
1671 throws RundeckApiException, RundeckApiLoginException,
1672 RundeckApiTokenException, IllegalArgumentException
1673 {
1674 AssertUtil.notNull(jobId, "jobId is mandatory to delete executions!");
1675 return new ApiCall(this).delete(
1676 new ApiPathBuilder("/job/",jobId,"/executions"),
1677 new DeleteExecutionsResponseParser( "/deleteExecutions")
1678 );
1679 }
1680
1681 /**
1682 * Delete a set of executions, identified by the given IDs
1683 *
1684 * @param executionIds set of identifiers for the executions - mandatory
1685 * @return a {@link DeleteExecutionsResponse} instance - won't be null
1686 * @throws RundeckApiException in case of error when calling the API (non-existent execution with this ID)
1687 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1688 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1689 * @throws IllegalArgumentException if the executionIds is null
1690 */
1691 public DeleteExecutionsResponse deleteExecutions(final Set<Long> executionIds)
1692 throws RundeckApiException, RundeckApiLoginException,
1693 RundeckApiTokenException, IllegalArgumentException
1694 {
1695 AssertUtil.notNull(executionIds, "executionIds is mandatory to delete executions!");
1696 if (executionIds.size() < 1) {
1697 throw new IllegalArgumentException("executionIds cannot be empty");
1698 }
1699 final ApiPathBuilder apiPath = new ApiPathBuilder("/executions/delete").xml(
1700 new DeleteExecutionsGenerator(executionIds)
1701 );
1702 return new ApiCall(this).post(
1703 apiPath,
1704 new DeleteExecutionsResponseParser( "/deleteExecutions")
1705 );
1706 }
1707
1708 /**
1709 * Delete a single execution, identified by the given ID
1710 *
1711 * @param executionId identifier for the execution - mandatory
1712 * @throws RundeckApiException in case of error when calling the API (non-existent execution with this ID)
1713 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1714 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1715 * @throws IllegalArgumentException if the executionId is null
1716 */
1717 public void deleteExecution(final Long executionId)
1718 throws RundeckApiException, RundeckApiLoginException,
1719 RundeckApiTokenException, IllegalArgumentException
1720 {
1721 AssertUtil.notNull(executionId, "executionId is mandatory to delete an execution!");
1722 new ApiCall(this).delete(new ApiPathBuilder("/execution/", executionId.toString()));
1723 }
1724
1725 /*
1726 * History
1727 */
1728
1729 /**
1730 * Get the (events) history for the given project
1731 *
1732 * @param project name of the project - mandatory
1733 * @return a {@link RundeckHistory} instance - won't be null
1734 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
1735 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1736 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1737 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
1738 * @see #getHistory(String, String, String, String, String, Date, Date, Long, Long)
1739 */
1740 public RundeckHistory getHistory(String project) throws RundeckApiException, RundeckApiLoginException,
1741 RundeckApiTokenException, IllegalArgumentException {
1742 return getHistory(project, null, null,(String) null, (String) null, null, null, null, null);
1743 }
1744
1745 /**
1746 * Get the (events) history for the given project
1747 *
1748 * @param project name of the project - mandatory
1749 * @param max number of results to return - optional (default to 20)
1750 * @param offset the 0-indexed offset for the first result to return - optional (default to O)
1751 * @return a {@link RundeckHistory} instance - won't be null
1752 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
1753 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1754 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1755 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
1756 * @see #getHistory(String, String, String, String, String, Date, Date, Long, Long)
1757 */
1758 public RundeckHistory getHistory(String project, Long max, Long offset) throws RundeckApiException,
1759 RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
1760 return getHistory(project, null, null, (String)null, (String)null, null, null, max, offset);
1761 }
1762
1763 /**
1764 * Get the (events) history for the given project
1765 *
1766 * @param project name of the project - mandatory
1767 * @param jobId include only events matching the given job ID - optional
1768 * @param reportId include only events matching the given report ID - optional
1769 * @param user include only events created by the given user - optional
1770 * @return a {@link RundeckHistory} instance - won't be null
1771 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
1772 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1773 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1774 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
1775 * @see #getHistory(String, String, String, String, String, Date, Date, Long, Long)
1776 */
1777 public RundeckHistory getHistory(String project, String jobId, String reportId, String user)
1778 throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
1779 return getHistory(project, jobId, reportId, user, null, null, null, null, null);
1780 }
1781
1782 /**
1783 * Get the (events) history for the given project
1784 *
1785 * @param project name of the project - mandatory
1786 * @param jobId include only events matching the given job ID - optional
1787 * @param reportId include only events matching the given report ID - optional
1788 * @param user include only events created by the given user - optional
1789 * @param max number of results to return - optional (default to 20)
1790 * @param offset the 0-indexed offset for the first result to return - optional (default to O)
1791 * @return a {@link RundeckHistory} instance - won't be null
1792 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
1793 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1794 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1795 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
1796 * @see #getHistory(String, String, String, String, String, Date, Date, Long, Long)
1797 */
1798 public RundeckHistory getHistory(String project, String jobId, String reportId, String user, Long max, Long offset)
1799 throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
1800 return getHistory(project, jobId, reportId, user, null, null, null, max, offset);
1801 }
1802
1803 /**
1804 * Get the (events) history for the given project
1805 *
1806 * @param project name of the project - mandatory
1807 * @param recent include only events matching the given period of time. Format : "XY", where X is an integer, and Y
1808 * is one of : "h" (hour), "d" (day), "w" (week), "m" (month), "y" (year). Example : "2w" (= last 2
1809 * weeks), "5d" (= last 5 days), etc. Optional.
1810 * @return a {@link RundeckHistory} instance - won't be null
1811 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
1812 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1813 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1814 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
1815 * @see #getHistory(String, String, String, String, String, Date, Date, Long, Long)
1816 */
1817 public RundeckHistory getHistory(String project, String recent) throws RundeckApiException,
1818 RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
1819 return getHistory(project, null, null, null, recent, null, null, null, null);
1820 }
1821
1822 /**
1823 * Get the (events) history for the given project
1824 *
1825 * @param project name of the project - mandatory
1826 * @param recent include only events matching the given period of time. Format : "XY", where X is an integer, and Y
1827 * is one of : "h" (hour), "d" (day), "w" (week), "m" (month), "y" (year). Example : "2w" (= last 2
1828 * weeks), "5d" (= last 5 days), etc. Optional.
1829 * @param max number of results to return - optional (default to 20)
1830 * @param offset the 0-indexed offset for the first result to return - optional (default to O)
1831 * @return a {@link RundeckHistory} instance - won't be null
1832 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
1833 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1834 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1835 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
1836 * @see #getHistory(String, String, String, String, String, Date, Date, Long, Long)
1837 */
1838 public RundeckHistory getHistory(String project, String recent, Long max, Long offset) throws RundeckApiException,
1839 RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
1840 return getHistory(project, null, null, null, recent, null, null, max, offset);
1841 }
1842
1843 /**
1844 * Get the (events) history for the given project
1845 *
1846 * @param project name of the project - mandatory
1847 * @param begin date for the earlier events to retrieve - optional
1848 * @param end date for the latest events to retrieve - optional
1849 * @return a {@link RundeckHistory} instance - won't be null
1850 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
1851 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1852 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1853 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
1854 * @see #getHistory(String, String, String, String, String, Date, Date, Long, Long)
1855 */
1856 public RundeckHistory getHistory(String project, Date begin, Date end) throws RundeckApiException,
1857 RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
1858 return getHistory(project, null, null, (String)null, (String)null, begin, end, null, null);
1859 }
1860
1861 /**
1862 * Get the (events) history for the given project
1863 *
1864 * @param project name of the project - mandatory
1865 * @param begin date for the earlier events to retrieve - optional
1866 * @param end date for the latest events to retrieve - optional
1867 * @param max number of results to return - optional (default to 20)
1868 * @param offset the 0-indexed offset for the first result to return - optional (default to O)
1869 * @return a {@link RundeckHistory} instance - won't be null
1870 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
1871 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1872 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1873 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
1874 * @see #getHistory(String, String, String, String, String, Date, Date, Long, Long)
1875 */
1876 public RundeckHistory getHistory(String project, Date begin, Date end, Long max, Long offset)
1877 throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
1878 return getHistory(project, null, null, (String)null, (String) null, begin, end, max, offset);
1879 }
1880
1881 /**
1882 * Get the (events) history for the given project
1883 *
1884 * @param project name of the project - mandatory
1885 * @param jobId include only events matching the given job ID - optional
1886 * @param reportId include only events matching the given report ID - optional
1887 * @param user include only events created by the given user - optional
1888 * @param recent include only events matching the given period of time. Format : "XY", where X is an integer, and Y
1889 * is one of : "h" (hour), "d" (day), "w" (week), "m" (month), "y" (year). Example : "2w" (= last 2
1890 * weeks), "5d" (= last 5 days), etc. Optional.
1891 * @param begin date for the earlier events to retrieve - optional
1892 * @param end date for the latest events to retrieve - optional
1893 * @param max number of results to return - optional (default to 20)
1894 * @param offset the 0-indexed offset for the first result to return - optional (default to O)
1895 * @return a {@link RundeckHistory} instance - won't be null
1896 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
1897 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1898 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1899 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
1900 */
1901 public RundeckHistory getHistory(String project, String jobId, String reportId, String user, String recent,
1902 Date begin, Date end, Long max, Long offset) throws RundeckApiException, RundeckApiLoginException,
1903 RundeckApiTokenException, IllegalArgumentException {
1904 AssertUtil.notBlank(project, "project is mandatory to get the history !");
1905 return new ApiCall(this).get(new ApiPathBuilder("/history").param("project", project)
1906 .param("jobIdFilter", jobId)
1907 .param("reportIdFilter", reportId)
1908 .param("userFilter", user)
1909 .param("recentFilter", recent)
1910 .param("begin", begin)
1911 .param("end", end)
1912 .param("max", max)
1913 .param("offset", offset),
1914 new HistoryParser("/events"));
1915 }
1916
1917 /**
1918 * Get the (events) history for the given project
1919 *
1920 * @param project name of the project - mandatory
1921 * @param includeJobNames list of job names ("group/name") to include results for
1922 * @param excludeJobNames list of job names ("group/name") to exclude results for
1923 * @param user include only events created by the given user - optional
1924 * @param recent include only events matching the given period of time. Format : "XY", where X is an
1925 * integer, and Y is one of : "h" (hour), "d" (day), "w" (week), "m" (month), "y" (year).
1926 * Example : "2w" (= last 2 weeks), "5d" (= last 5 days), etc. Optional.
1927 * @param begin date for the earlier events to retrieve - optional
1928 * @param end date for the latest events to retrieve - optional
1929 * @param max number of results to return - optional (default to 20)
1930 * @param offset the 0-indexed offset for the first result to return - optional (default to O)
1931 *
1932 * @return a {@link RundeckHistory} instance - won't be null
1933 *
1934 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
1935 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1936 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1937 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
1938 */
1939 public RundeckHistory getHistory(String project,
1940 String user,
1941 String recent,
1942 List<String> includeJobNames,
1943 List<String> excludeJobNames,
1944 Date begin,
1945 Date end,
1946 Long max,
1947 Long offset)
1948 throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
1949
1950 AssertUtil.notBlank(project, "project is mandatory to get the history !");
1951 final ApiPathBuilder builder = new ApiPathBuilder("/history").param("project", project)
1952 .field("jobListFilter", includeJobNames)
1953 .field("excludeJobListFilter", excludeJobNames)
1954 .param("userFilter", user)
1955 .param("recentFilter", recent)
1956 .param("begin", begin)
1957 .param("end", end)
1958 .param("max", max)
1959 .param("offset", offset);
1960
1961 return new ApiCall(this).postOrGet(builder, new HistoryParser("/events"));
1962 }
1963
1964 /*
1965 * Nodes
1966 */
1967
1968 /**
1969 * List all nodes (for all projects)
1970 *
1971 * @return a {@link List} of {@link RundeckNode} : might be empty, but won't be null
1972 * @throws RundeckApiException in case of error when calling the API
1973 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1974 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1975 */
1976 public List<RundeckNode> getNodes() throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException {
1977 List<RundeckNode> nodes = new ArrayList<RundeckNode>();
1978 for (RundeckProject project : getProjects()) {
1979 nodes.addAll(getNodes(project.getName()));
1980 }
1981 return nodes;
1982 }
1983
1984 /**
1985 * List all nodes that belongs to the given project
1986 *
1987 * @param project name of the project - mandatory
1988 * @return a {@link List} of {@link RundeckNode} : might be empty, but won't be null
1989 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
1990 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
1991 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
1992 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
1993 * @see #getNodes(String, Properties)
1994 */
1995 public List<RundeckNode> getNodes(String project) throws RundeckApiException, RundeckApiLoginException,
1996 RundeckApiTokenException, IllegalArgumentException {
1997 return getNodes(project, null);
1998 }
1999
2000 /**
2001 * List nodes that belongs to the given project
2002 *
2003 * @param project name of the project - mandatory
2004 * @param nodeFilters for filtering the nodes - optional. See {@link NodeFiltersBuilder}
2005 * @return a {@link List} of {@link RundeckNode} : might be empty, but won't be null
2006 * @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
2007 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
2008 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
2009 * @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
2010 */
2011 public List<RundeckNode> getNodes(String project, Properties nodeFilters) throws RundeckApiException,
2012 RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
2013 AssertUtil.notBlank(project, "project is mandatory to get all nodes !");
2014 return new ApiCall(this).get(new ApiPathBuilder("/resources").param("project", project)
2015 .nodeFilters(nodeFilters),
2016 new ListParser<RundeckNode>(new NodeParser(), "project/node"));
2017 }
2018
2019 /**
2020 * Get the definition of a single node
2021 *
2022 * @param name of the node - mandatory
2023 * @param project name of the project - mandatory
2024 * @return a {@link RundeckNode} instance - won't be null
2025 * @throws RundeckApiException in case of error when calling the API (non-existent name or project with this name)
2026 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
2027 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
2028 * @throws IllegalArgumentException if the name or project is blank (null, empty or whitespace)
2029 */
2030 public RundeckNode getNode(String name, String project) throws RundeckApiException, RundeckApiLoginException,
2031 RundeckApiTokenException, IllegalArgumentException {
2032 AssertUtil.notBlank(name, "the name of the node is mandatory to get a node !");
2033 AssertUtil.notBlank(project, "project is mandatory to get a node !");
2034 return new ApiCall(this).get(new ApiPathBuilder("/resource/", name).param("project", project),
2035 new NodeParser("project/node"));
2036 }
2037
2038 /**
2039 * Get the output of a job execution
2040 *
2041 * @param executionId id of the execution - mandatory
2042 * @return an {@link InputStream} instance, not linked to any network resources - won't be null
2043 * @throws RundeckApiException in case of error when calling the API (non-existent name or project with this name)
2044 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
2045 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
2046 * @throws IllegalArgumentException if the name or project is blank (null, empty or whitespace)
2047 */
2048 public InputStream getOutput(String executionId) throws RundeckApiException, RundeckApiLoginException,
2049 RundeckApiTokenException, IllegalArgumentException {
2050 AssertUtil.notBlank(executionId, "the execution id is mandatory to get execution output !");
2051 return new ApiCall(this).getNonApi(new ApiPathBuilder("/execution/downloadOutput/", executionId));
2052 }
2053
2054 /**
2055 * Get the html page of the user's profile
2056 *
2057 * @param username - mandatory
2058 * @return an {@link InputStream} instance, not linked to any network resources - won't be null
2059 * @throws RundeckApiException in case of error when calling the API (non-existent name or project with this name)
2060 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
2061 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
2062 * @throws IllegalArgumentException if the name or project is blank (null, empty or whitespace)
2063 */
2064 public InputStream getProfilePage(String username) throws RundeckApiException, RundeckApiLoginException,
2065 RundeckApiTokenException, IllegalArgumentException {
2066 AssertUtil.notBlank(username, "the username is mandatory to get profile page !");
2067 return new ApiCall(this).getNonApi(new ApiPathBuilder("/user/profile?login=", username));
2068 }
2069
2070
2071 /**
2072 * Generate a new token and get the result page (which is the html page of the user's profile)
2073 *
2074 * @param username - mandatory
2075 * @return an {@link InputStream} instance, not linked to any network resources - won't be null
2076 * @throws RundeckApiException in case of error when calling the API (non-existent name or project with this name)
2077 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
2078 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
2079 * @throws IllegalArgumentException if the name or project is blank (null, empty or whitespace)
2080 */
2081 public InputStream generateToken(String username) throws RundeckApiException, RundeckApiLoginException,
2082 RundeckApiTokenException, IllegalArgumentException {
2083 AssertUtil.notBlank(username, "the username is mandatory to generate the token");
2084 return new ApiCall(this).getNonApi(new ApiPathBuilder("/user/generateApiToken?login=", username));
2085 }
2086
2087
2088 /**
2089 * Get the execution output of the given job
2090 *
2091 * @param executionId identifier of the execution - mandatory
2092 * @param offset byte offset to read from in the file. 0 indicates the beginning.
2093 * @param lastlines nnumber of lines to retrieve from the end of the available output. If specified it will override the offset value and return only the specified number of lines at the end of the log.
2094 * @param lastmod epoch datestamp in milliseconds, return results only if modification changed since the specified date OR if more data is available at the given offset
2095 * @param maxlines maximum number of lines to retrieve forward from the specified offset.
2096 * @return {@link RundeckOutput}
2097 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
2098 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
2099 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
2100 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
2101 */
2102 public RundeckOutput getExecutionOutput(Long executionId, int offset, int lastlines, long lastmod, int maxlines)
2103 throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
2104 AssertUtil.notNull(executionId, "executionId is mandatory to get the output of a job execution!");
2105 ApiPathBuilder param = new ApiPathBuilder(
2106 "/execution/", executionId.toString(),
2107 "/output")
2108 .param("offset", offset);
2109 if (lastlines > 0) {
2110 param.param("lastlines", lastlines);
2111 }
2112 if (lastmod >= 0) {
2113 param.param("lastmod", lastmod);
2114 }
2115 if (maxlines > 0) {
2116 param.param("maxlines", maxlines);
2117 }
2118 return new ApiCall(this).get(param,
2119 new OutputParser("/output", createOutputEntryParser()));
2120 }
2121 /**
2122 * Get the execution state of the given execution
2123 *
2124 * @param executionId identifier of the execution - mandatory
2125 * @return {@link RundeckExecutionState} the execution state
2126 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
2127 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
2128 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
2129 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
2130 */
2131 public RundeckExecutionState getExecutionState(Long executionId)
2132 throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
2133 AssertUtil.notNull(executionId, "executionId is mandatory to get the state of an execution!");
2134 ApiPathBuilder param = new ApiPathBuilder(
2135 "/execution/", executionId.toString(),
2136 "/state");
2137
2138 return new ApiCall(this).get(param, new ExecutionStateParser("/executionState"));
2139 }
2140
2141 /**
2142 * Get the execution output of the given execution on the specified node
2143 *
2144 * @param executionId identifier of the execution - mandatory
2145 * @param nodeName name of the node
2146 * @param offset byte offset to read from in the file. 0 indicates the beginning.
2147 * @param lastlines nnumber of lines to retrieve from the end of the available output. If specified it will
2148 * override the offset value and return only the specified number of lines at the end of the
2149 * log.
2150 * @param lastmod epoch datestamp in milliseconds, return results only if modification changed since the
2151 * specified date OR if more data is available at the given offset
2152 * @param maxlines maximum number of lines to retrieve forward from the specified offset.
2153 *
2154 * @return {@link RundeckOutput}
2155 *
2156 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
2157 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
2158 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
2159 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
2160 */
2161 public RundeckOutput getExecutionOutputForNode(Long executionId, String nodeName, int offset, int lastlines,
2162 long lastmod, int maxlines)
2163 throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
2164 AssertUtil.notNull(executionId, "executionId is mandatory to get the output of a job execution!");
2165 AssertUtil.notNull(nodeName, "nodeName is mandatory to get the output of a job execution!");
2166 ApiPathBuilder param = new ApiPathBuilder(
2167 "/execution/", executionId.toString(),
2168 "/output/node/", nodeName)
2169 .param("offset", offset);
2170 if(lastlines>0) {
2171 param.param("lastlines", lastlines);
2172 }
2173 if(lastmod>=0) {
2174 param.param("lastmod", lastmod);
2175 }
2176 if(maxlines>0) {
2177 param.param("maxlines", maxlines);
2178 }
2179 return new ApiCall(this).get(param,
2180 new OutputParser("/output", createOutputEntryParser()));
2181 }
2182 /**
2183 * Get the execution output of the given execution for the specified step
2184 *
2185 * @param executionId identifier of the execution - mandatory
2186 * @param stepCtx identifier for the step
2187 * @param offset byte offset to read from in the file. 0 indicates the beginning.
2188 * @param lastlines nnumber of lines to retrieve from the end of the available output. If specified it will
2189 * override the offset value and return only the specified number of lines at the end of the
2190 * log.
2191 * @param lastmod epoch datestamp in milliseconds, return results only if modification changed since the
2192 * specified date OR if more data is available at the given offset
2193 * @param maxlines maximum number of lines to retrieve forward from the specified offset.
2194 *
2195 * @return {@link RundeckOutput}
2196 *
2197 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
2198 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
2199 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
2200 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
2201 */
2202 public RundeckOutput getExecutionOutputForStep(Long executionId, String stepCtx, int offset, int lastlines,
2203 long lastmod, int maxlines)
2204 throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
2205 AssertUtil.notNull(executionId, "executionId is mandatory to get the output of a job execution!");
2206 AssertUtil.notNull(stepCtx, "stepCtx is mandatory to get the output of a job execution!");
2207 ApiPathBuilder param = new ApiPathBuilder(
2208 "/execution/", executionId.toString(),
2209 "/output/step/", stepCtx)
2210 .param("offset", offset);
2211 if (lastlines > 0) {
2212 param.param("lastlines", lastlines);
2213 }
2214 if (lastmod >= 0) {
2215 param.param("lastmod", lastmod);
2216 }
2217 if (maxlines > 0) {
2218 param.param("maxlines", maxlines);
2219 }
2220 return new ApiCall(this).get(param,
2221 new OutputParser("/output", createOutputEntryParser()));
2222 }
2223 /**
2224 * Get the execution output of the given execution for the specified step
2225 *
2226 * @param executionId identifier of the execution - mandatory
2227 * @param stepCtx identifier for the step
2228 * @param offset byte offset to read from in the file. 0 indicates the beginning.
2229 * @param lastlines nnumber of lines to retrieve from the end of the available output. If specified it will
2230 * override the offset value and return only the specified number of lines at the end of the
2231 * log.
2232 * @param lastmod epoch datestamp in milliseconds, return results only if modification changed since the
2233 * specified date OR if more data is available at the given offset
2234 * @param maxlines maximum number of lines to retrieve forward from the specified offset.
2235 *
2236 * @return {@link RundeckOutput}
2237 *
2238 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
2239 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
2240 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
2241 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
2242 */
2243 public RundeckOutput getExecutionOutputForNodeAndStep(Long executionId, String nodeName, String stepCtx,
2244 int offset, int lastlines,
2245 long lastmod, int maxlines)
2246 throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
2247 AssertUtil.notNull(executionId, "executionId is mandatory to get the output of a job execution!");
2248 AssertUtil.notNull(nodeName, "nodeName is mandatory to get the output of a job execution!");
2249 AssertUtil.notNull(stepCtx, "stepCtx is mandatory to get the output of a job execution!");
2250 ApiPathBuilder param = new ApiPathBuilder(
2251 "/execution/", executionId.toString(),
2252 "/output/node/", nodeName,
2253 "/step/", stepCtx)
2254 .param("offset", offset);
2255 if (lastlines > 0) {
2256 param.param("lastlines", lastlines);
2257 }
2258 if (lastmod >= 0) {
2259 param.param("lastmod", lastmod);
2260 }
2261 if (maxlines > 0) {
2262 param.param("maxlines", maxlines);
2263 }
2264 return new ApiCall(this).get(param,
2265 new OutputParser("/output", createOutputEntryParser()));
2266 }
2267
2268
2269 /**
2270 * Get the execution output of the given job
2271 *
2272 * @param executionId identifier of the execution - mandatory
2273 * @param offset byte offset to read from in the file. 0 indicates the beginning.
2274 * @param lastmod epoch datestamp in milliseconds, return results only if modification changed since the specified date OR if more data is available at the given offset
2275 * @param maxlines maximum number of lines to retrieve forward from the specified offset.
2276 * @return {@link RundeckOutput}
2277 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
2278 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
2279 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
2280 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
2281 */
2282 public RundeckOutput getExecutionOutput(Long executionId, int offset, long lastmod, int maxlines)
2283 throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
2284 AssertUtil.notNull(executionId, "executionId is mandatory to get the output of a job execution!");
2285 ApiPathBuilder param = new ApiPathBuilder("/execution/", executionId.toString(), "/output")
2286 .param("offset", offset);
2287 if (lastmod >= 0) {
2288 param.param("lastmod", lastmod);
2289 }
2290 if (maxlines > 0) {
2291 param.param("maxlines", maxlines);
2292 }
2293 return new ApiCall(this).get(param, new OutputParser("/output", createOutputEntryParser()));
2294 }
2295 /**
2296 * Get the execution state output sequence of the given job
2297 *
2298 * @param executionId identifier of the execution - mandatory
2299 * @param stateOnly if true, include only state change output entries, otherwise include state and log entries
2300 * @param offset byte offset to read from in the file. 0 indicates the beginning.
2301 * @param lastmod epoch datestamp in milliseconds, return results only if modification changed since the specified date OR if more data is available at the given offset
2302 * @param maxlines maximum number of lines to retrieve forward from the specified offset.
2303 * @return {@link RundeckOutput}
2304 * @throws RundeckApiException in case of error when calling the API (non-existent job with this ID)
2305 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
2306 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
2307 * @throws IllegalArgumentException if the jobId is blank (null, empty or whitespace)
2308 */
2309 public RundeckOutput getExecutionOutputState(Long executionId, boolean stateOnly, int offset, long lastmod,
2310 int maxlines)
2311 throws RundeckApiException, RundeckApiLoginException, RundeckApiTokenException, IllegalArgumentException {
2312 AssertUtil.notNull(executionId, "executionId is mandatory to get the output of a job execution!");
2313 ApiPathBuilder param = new ApiPathBuilder("/execution/", executionId.toString(), "/output/state")
2314 .param("offset", offset);
2315 if (lastmod >= 0) {
2316 param.param("lastmod", lastmod);
2317 }
2318 if (maxlines > 0) {
2319 param.param("maxlines", maxlines);
2320 }
2321 if(stateOnly) {
2322 param.param("stateOnly", true);
2323 }
2324 return new ApiCall(this).get(param, new OutputParser("/output", createOutputEntryParser()));
2325 }
2326
2327 private OutputEntryParser createOutputEntryParser() {
2328 if (getApiVersion() <= Version.V5.versionNumber) {
2329 return new OutputEntryParserV5();
2330 }else{
2331 return new OutputEntryParser();
2332 }
2333 }
2334
2335
2336 /*
2337 * System Info
2338 */
2339
2340 /**
2341 * Get system informations about the Rundeck server
2342 *
2343 * @return a {@link RundeckSystemInfo} instance - won't be null
2344 * @throws RundeckApiException in case of error when calling the API
2345 * @throws RundeckApiLoginException if the login fails (in case of login-based authentication)
2346 * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication)
2347 */
2348 public RundeckSystemInfo getSystemInfo() throws RundeckApiException, RundeckApiLoginException,
2349 RundeckApiTokenException {
2350 return new ApiCall(this).get(new ApiPathBuilder("/system/info"), new SystemInfoParser("/system"));
2351 }
2352
2353
2354 /*
2355 * API token
2356 */
2357
2358 /**
2359 * List API tokens for a user.
2360 * @param user username
2361 * @return list of tokens
2362 * @throws RundeckApiException
2363 */
2364 public List<RundeckToken> listApiTokens(final String user) throws RundeckApiException {
2365 AssertUtil.notNull(user, "user is mandatory to list API tokens for a user.");
2366 return new ApiCall(this).
2367 get(new ApiPathBuilder("/tokens/", user),
2368 new ListParser<RundeckToken>(new RundeckTokenParser(), "/tokens/token"));
2369 }
2370
2371 /**
2372 * List all API tokens
2373 * @return list of tokens
2374 * @throws RundeckApiException
2375 */
2376 public List<RundeckToken> listApiTokens() throws RundeckApiException {
2377 return new ApiCall(this).
2378 get(new ApiPathBuilder("/tokens"),
2379 new ListParser<RundeckToken>(new RundeckTokenParser(), "/tokens/token"));
2380 }
2381
2382 /**
2383 * Generate an API token for a user.
2384 * @param user
2385 * @return
2386 * @throws RundeckApiException
2387 */
2388 public String generateApiToken(final String user) throws RundeckApiException{
2389 AssertUtil.notNull(user, "user is mandatory to generate an API token for a user.");
2390 RundeckToken result = new ApiCall(this).
2391 post(new ApiPathBuilder("/tokens/", user).emptyContent(),
2392 new RundeckTokenParser("/token"));
2393 return result.getToken();
2394 }
2395 /**
2396 * Delete an existing token
2397 * @param token
2398 * @return
2399 * @throws RundeckApiException
2400 */
2401 public boolean deleteApiToken(final String token) throws RundeckApiException{
2402 AssertUtil.notNull(token, "token is mandatory to delete an API token.");
2403 new ApiCall(this).delete(new ApiPathBuilder("/token/", token));
2404 return true;
2405 }
2406 /**
2407 * Return user info for an existing token
2408 * @param token
2409 * @return token info
2410 * @throws RundeckApiException
2411 */
2412 public RundeckToken getApiToken(final String token) throws RundeckApiException{
2413 AssertUtil.notNull(token, "token is mandatory to get an API token.");
2414 return new ApiCall(this).get(new ApiPathBuilder("/token/", token), new RundeckTokenParser("/token"));
2415 }
2416
2417 /**
2418 * Store an key file
2419 * @param path ssh key storage path, must start with "keys/"
2420 * @param keyfile key file
2421 * @param privateKey true to store private key, false to store public key
2422 * @return the key resource
2423 * @throws RundeckApiException
2424 */
2425 public KeyResource storeKey(final String path, final File keyfile, boolean privateKey) throws RundeckApiException{
2426 AssertUtil.notNull(path, "path is mandatory to store an key.");
2427 AssertUtil.notNull(keyfile, "keyfile is mandatory to store an key.");
2428 if (!path.startsWith(STORAGE_KEYS_PATH)) {
2429 throw new IllegalArgumentException("key storage path must start with: " + STORAGE_KEYS_PATH);
2430 }
2431 return new ApiCall(this).post(
2432 new ApiPathBuilder(STORAGE_ROOT_PATH, path).content(
2433 privateKey ? "application/octet-stream" : "application/pgp-keys",
2434 keyfile
2435 ),
2436 new SSHKeyResourceParser("/resource")
2437 );
2438 }
2439
2440 /**
2441 * Get metadata for an key file
2442 *
2443 * @param path ssh key storage path, must start with "keys/"
2444 *
2445 * @return the ssh key resource
2446 *
2447 * @throws RundeckApiException if there is an error, or if the path is a directory not a file
2448 */
2449 public KeyResource getKey(final String path) throws RundeckApiException {
2450 AssertUtil.notNull(path, "path is mandatory to get an key.");
2451 if (!path.startsWith(STORAGE_KEYS_PATH)) {
2452 throw new IllegalArgumentException("key storage path must start with: " + STORAGE_KEYS_PATH);
2453 }
2454 KeyResource storageResource = new ApiCall(this).get(
2455 new ApiPathBuilder(STORAGE_ROOT_PATH, path),
2456 new SSHKeyResourceParser("/resource")
2457 );
2458 if (storageResource.isDirectory()) {
2459 throw new RundeckApiException("Key Path is a directory: " + path);
2460 }
2461 return storageResource;
2462 }
2463
2464 /**
2465 * Get content for a public key file
2466 * @param path ssh key storage path, must start with "keys/"
2467 * @param out outputstream to write data to
2468 *
2469 * @return length of written data
2470 * @throws RundeckApiException
2471 */
2472 public int getPublicKeyContent(final String path, final OutputStream out) throws
2473 RundeckApiException, IOException {
2474 AssertUtil.notNull(path, "path is mandatory to get an key.");
2475 if (!path.startsWith(STORAGE_KEYS_PATH)) {
2476 throw new IllegalArgumentException("key storage path must start with: " + STORAGE_KEYS_PATH);
2477 }
2478 try {
2479 return new ApiCall(this).get(
2480 new ApiPathBuilder(STORAGE_ROOT_PATH, path)
2481 .accept("application/pgp-keys")
2482 .requireContentType("application/pgp-keys"),
2483 out
2484 );
2485 } catch (RundeckApiException.RundeckApiHttpContentTypeException e) {
2486 throw new RundeckApiException("Requested Key path was not a Public key: " + path, e);
2487 }
2488 }
2489
2490 /**
2491 * Get content for a public key file
2492 * @param path ssh key storage path, must start with "keys/"
2493 * @param out file to write data to
2494 * @return length of written data
2495 * @throws RundeckApiException
2496 */
2497 public int getPublicKeyContent(final String path, final File out) throws
2498 RundeckApiException, IOException {
2499 final FileOutputStream fileOutputStream = new FileOutputStream(out);
2500 try {
2501 return getPublicKeyContent(path, fileOutputStream);
2502 }finally {
2503 fileOutputStream.close();
2504 }
2505 }
2506
2507 /**
2508 * List contents of root key directory
2509 *
2510 * @return list of key resources
2511 * @throws RundeckApiException
2512 */
2513 public List<KeyResource> listKeyDirectoryRoot() throws RundeckApiException {
2514 return listKeyDirectory(STORAGE_KEYS_PATH);
2515 }
2516 /**
2517 * List contents of key directory
2518 *
2519 * @param path ssh key storage path, must start with "keys/"
2520 *
2521 * @throws RundeckApiException if there is an error, or if the path is a file not a directory
2522 */
2523 public List<KeyResource> listKeyDirectory(final String path) throws RundeckApiException {
2524 AssertUtil.notNull(path, "path is mandatory to get an key.");
2525 if (!path.startsWith(STORAGE_KEYS_PATH)) {
2526 throw new IllegalArgumentException("key storage path must start with: " + STORAGE_KEYS_PATH);
2527 }
2528 KeyResource storageResource = new ApiCall(this).get(
2529 new ApiPathBuilder(STORAGE_ROOT_PATH, path),
2530 new SSHKeyResourceParser("/resource")
2531 );
2532 if(!storageResource.isDirectory()) {
2533 throw new RundeckApiException("key path is not a directory path: " + path);
2534 }
2535 return storageResource.getDirectoryContents();
2536 }
2537
2538 /**
2539 * Delete an key file
2540 * @param path a path to a key file, must start with "keys/"
2541 */
2542 public void deleteKey(final String path){
2543 AssertUtil.notNull(path, "path is mandatory to delete an key.");
2544 if (!path.startsWith(STORAGE_KEYS_PATH)) {
2545 throw new IllegalArgumentException("key storage path must start with: " + STORAGE_KEYS_PATH);
2546 }
2547 new ApiCall(this).delete(new ApiPathBuilder(STORAGE_ROOT_PATH, path));
2548 }
2549
2550 /**
2551 * @return the URL of the Rundeck instance ("http://localhost:4440", "http://rundeck.your-compagny.com/", etc)
2552 */
2553 public String getUrl() {
2554 return url;
2555 }
2556
2557 /**
2558 * @return the auth-token used for authentication on the Rundeck instance (null if using login-based or session-based auth)
2559 */
2560 public String getToken() {
2561 return token;
2562 }
2563
2564 /**
2565 * @return the login used for authentication on the Rundeck instance (null if using token-based or session-based auth)
2566 */
2567 public String getLogin() {
2568 return login;
2569 }
2570
2571 /**
2572 * @return the password used for authentication on the Rundeck instance (null if using token-based or session-based auth)
2573 */
2574 public String getPassword() {
2575 return password;
2576 }
2577
2578 /**
2579 * @return the sessionID used for authentication on the Rundeck instance (null if using login-based or token-based auth)
2580 */
2581 public String getSessionID() {
2582 return sessionID;
2583 }
2584
2585 @Override
2586 public String toString() {
2587 StringBuilder str = new StringBuilder();
2588 str.append("RundeckClient ").append(API_VERSION);
2589 str.append(" [").append(url).append("] ");
2590 if (token != null) {
2591 str.append("(token=").append(token).append(")");
2592 } else {
2593 str.append("(credentials=").append(login).append("|").append(password).append(")");
2594 }
2595 return str.toString();
2596 }
2597
2598 @Override
2599 public int hashCode() {
2600 final int prime = 31;
2601 int result = 1;
2602 result = prime * result + ((login == null) ? 0 : login.hashCode());
2603 result = prime * result + ((password == null) ? 0 : password.hashCode());
2604 result = prime * result + ((token == null) ? 0 : token.hashCode());
2605 result = prime * result + ((url == null) ? 0 : url.hashCode());
2606 return result;
2607 }
2608
2609 @Override
2610 public boolean equals(Object obj) {
2611 if (this == obj)
2612 return true;
2613 if (obj == null)
2614 return false;
2615 if (getClass() != obj.getClass())
2616 return false;
2617 RundeckClient other = (RundeckClient) obj;
2618 if (login == null) {
2619 if (other.login != null)
2620 return false;
2621 } else if (!login.equals(other.login))
2622 return false;
2623 if (password == null) {
2624 if (other.password != null)
2625 return false;
2626 } else if (!password.equals(other.password))
2627 return false;
2628 if (token == null) {
2629 if (other.token != null)
2630 return false;
2631 } else if (!token.equals(other.token))
2632 return false;
2633 if (url == null) {
2634 if (other.url != null)
2635 return false;
2636 } else if (!url.equals(other.url))
2637 return false;
2638 return true;
2639 }
2640
2641 }