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 }