mirror of
https://github.com/Fishwaldo/rundeck-api-java-client.git
synced 2025-07-07 05:28:21 +00:00
new feature : import jobs
This commit is contained in:
parent
b34a6e39db
commit
2cac570478
16 changed files with 610 additions and 9 deletions
5
pom.xml
5
pom.xml
|
@ -396,6 +396,11 @@
|
|||
<artifactId>httpclient</artifactId>
|
||||
<version>4.1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpmime</artifactId>
|
||||
<version>4.1.1</version>
|
||||
</dependency>
|
||||
<!-- Commons -->
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
|
|
|
@ -22,10 +22,12 @@
|
|||
<author>Vincent Behar</author>
|
||||
</properties>
|
||||
<body>
|
||||
<release version="1.1" date="Not Yet Released" description="Add missing features">
|
||||
<action dev="vbehar" type="add">Import jobs</action>
|
||||
<action dev="vbehar" type="add">Support for using an HTTP proxy</action>
|
||||
</release>
|
||||
<release version="1.0" date="2011-07-08" description="Use RunDeck REST API version 1 (RunDeck 1.2+)">
|
||||
<action dev="vbehar" type="add">
|
||||
Initial release
|
||||
</action>
|
||||
<action dev="vbehar" type="add">Initial release</action>
|
||||
</release>
|
||||
</body>
|
||||
</document>
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.rundeck.api;
|
|||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.ProxySelector;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
@ -26,6 +27,7 @@ import java.security.cert.CertificateException;
|
|||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.NameValuePair;
|
||||
|
@ -39,7 +41,11 @@ import org.apache.http.client.methods.HttpRequestBase;
|
|||
import org.apache.http.conn.scheme.Scheme;
|
||||
import org.apache.http.conn.ssl.SSLSocketFactory;
|
||||
import org.apache.http.conn.ssl.TrustStrategy;
|
||||
import org.apache.http.entity.mime.HttpMultipartMode;
|
||||
import org.apache.http.entity.mime.MultipartEntity;
|
||||
import org.apache.http.entity.mime.content.InputStreamBody;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.impl.conn.ProxySelectorRoutePlanner;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.protocol.HTTP;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
@ -138,6 +144,30 @@ class ApiCall {
|
|||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute an HTTP POST request to the RunDeck instance, on the given path. We will login first, and then execute
|
||||
* the API call. At the end, the given parser will be used to convert the response to a more useful result object.
|
||||
*
|
||||
* @param apiPath on which we will make the HTTP request - see {@link ApiPathBuilder}
|
||||
* @param parser used to parse the response
|
||||
* @return the result of the call, as formatted by the parser
|
||||
* @throws RundeckApiException in case of error when calling the API
|
||||
* @throws RundeckApiLoginException if the login fails
|
||||
*/
|
||||
public <T> T post(ApiPathBuilder apiPath, XmlNodeParser<T> parser) throws RundeckApiException,
|
||||
RundeckApiLoginException {
|
||||
HttpPost httpPost = new HttpPost(client.getUrl() + RundeckClient.API_ENDPOINT + apiPath);
|
||||
|
||||
// POST a multi-part request, with all attachments
|
||||
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
|
||||
for (Entry<String, InputStream> attachment : apiPath.getAttachments().entrySet()) {
|
||||
entity.addPart(attachment.getKey(), new InputStreamBody(attachment.getValue(), attachment.getKey()));
|
||||
}
|
||||
httpPost.setEntity(entity);
|
||||
|
||||
return execute(httpPost, parser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute an HTTP DELETE request to the RunDeck instance, on the given path. We will login first, and then execute
|
||||
* the API call. At the end, the given parser will be used to convert the response to a more useful result object.
|
||||
|
@ -316,6 +346,9 @@ class ApiCall {
|
|||
* @return an {@link HttpClient} instance - won't be null
|
||||
*/
|
||||
private HttpClient instantiateHttpClient() {
|
||||
DefaultHttpClient httpClient = new DefaultHttpClient();
|
||||
|
||||
// configure SSL
|
||||
SSLSocketFactory socketFactory = null;
|
||||
try {
|
||||
socketFactory = new SSLSocketFactory(new TrustStrategy() {
|
||||
|
@ -334,9 +367,13 @@ class ApiCall {
|
|||
} catch (KeyStoreException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
HttpClient httpClient = new DefaultHttpClient();
|
||||
httpClient.getConnectionManager().getSchemeRegistry().register(new Scheme("https", 443, socketFactory));
|
||||
|
||||
// configure proxy (use system env : http.proxyHost / http.proxyPort)
|
||||
System.setProperty("java.net.useSystemProxies", "true");
|
||||
httpClient.setRoutePlanner(new ProxySelectorRoutePlanner(httpClient.getConnectionManager().getSchemeRegistry(),
|
||||
ProxySelector.getDefault()));
|
||||
|
||||
return httpClient;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
*/
|
||||
package org.rundeck.api;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.rundeck.api.util.ParametersUtil;
|
||||
|
@ -29,7 +32,10 @@ class ApiPathBuilder {
|
|||
/** Internally, we store everything in a {@link StringBuilder} */
|
||||
private final StringBuilder apiPath;
|
||||
|
||||
/** Maker for using the right separator between parameters ("?" or "&") */
|
||||
/** When POSTing, we can add attachments */
|
||||
private final Map<String, InputStream> attachments;
|
||||
|
||||
/** Marker for using the right separator between parameters ("?" or "&") */
|
||||
private boolean firstParamDone = false;
|
||||
|
||||
/**
|
||||
|
@ -40,6 +46,7 @@ class ApiPathBuilder {
|
|||
*/
|
||||
public ApiPathBuilder(String... paths) {
|
||||
apiPath = new StringBuilder();
|
||||
attachments = new HashMap<String, InputStream>();
|
||||
if (paths != null) {
|
||||
for (String path : paths) {
|
||||
if (StringUtils.isNotBlank(path)) {
|
||||
|
@ -68,6 +75,22 @@ class ApiPathBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the given parameter (key and value). This will only append the parameter if it is not null, and make sure
|
||||
* to add the right separator ("?" or "&") before. The key and value will be separated by the "=" character. Also,
|
||||
* the value will be converted to lower-case.
|
||||
*
|
||||
* @param key of the parameter. Must not be null or empty
|
||||
* @param value of the parameter. May be null
|
||||
* @return this, for method chaining
|
||||
*/
|
||||
public ApiPathBuilder param(String key, Enum<?> value) {
|
||||
if (value != null) {
|
||||
param(key, StringUtils.lowerCase(value.toString()));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the given parameter (key and value). This will only append the parameter if it is not null, and make sure
|
||||
* to add the right separator ("?" or "&") before. The key and value will be separated by the "=" character.
|
||||
|
@ -129,6 +152,28 @@ class ApiPathBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* When POSTing a request, add the given {@link InputStream} as an attachment to the content of the request. This
|
||||
* will only add the stream if it is not null.
|
||||
*
|
||||
* @param name of the attachment. Must not be null or empty
|
||||
* @param stream. May be null
|
||||
* @return this, for method chaining
|
||||
*/
|
||||
public ApiPathBuilder attach(String name, InputStream stream) {
|
||||
if (stream != null) {
|
||||
attachments.put(name, stream);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return all attachments to be POSTed, with their names
|
||||
*/
|
||||
public Map<String, InputStream> getAttachments() {
|
||||
return attachments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return apiPath.toString();
|
||||
|
|
25
src/main/java/org/rundeck/api/FileType.java
Normal file
25
src/main/java/org/rundeck/api/FileType.java
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright 2011 Vincent Behar
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.rundeck.api;
|
||||
|
||||
/**
|
||||
* All supported types of files.
|
||||
*
|
||||
* @author Vincent Behar
|
||||
*/
|
||||
public enum FileType {
|
||||
XML, YAML;
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
package org.rundeck.api;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
|
@ -30,6 +31,8 @@ import org.rundeck.api.RundeckApiException.RundeckApiLoginException;
|
|||
import org.rundeck.api.domain.RundeckAbort;
|
||||
import org.rundeck.api.domain.RundeckExecution;
|
||||
import org.rundeck.api.domain.RundeckJob;
|
||||
import org.rundeck.api.domain.RundeckJobsImportMethod;
|
||||
import org.rundeck.api.domain.RundeckJobsImportResult;
|
||||
import org.rundeck.api.domain.RundeckNode;
|
||||
import org.rundeck.api.domain.RundeckProject;
|
||||
import org.rundeck.api.domain.RundeckSystemInfo;
|
||||
|
@ -37,6 +40,7 @@ import org.rundeck.api.domain.RundeckExecution.ExecutionStatus;
|
|||
import org.rundeck.api.parser.AbortParser;
|
||||
import org.rundeck.api.parser.ExecutionParser;
|
||||
import org.rundeck.api.parser.JobParser;
|
||||
import org.rundeck.api.parser.JobsImportResultParser;
|
||||
import org.rundeck.api.parser.ListParser;
|
||||
import org.rundeck.api.parser.NodeParser;
|
||||
import org.rundeck.api.parser.ProjectParser;
|
||||
|
@ -316,6 +320,173 @@ public class RundeckClient implements Serializable {
|
|||
return new ApiCall(this).get(new ApiPathBuilder("/job/", jobId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Import the definitions of jobs, from the given file
|
||||
*
|
||||
* @param filename of the file containing the jobs definitions - mandatory
|
||||
* @param fileType type of the file. See {@link FileType} - mandatory
|
||||
* @return a {@link RundeckJobsImportResult} instance - won't be null
|
||||
* @throws RundeckApiException in case of error when calling the API
|
||||
* @throws RundeckApiLoginException if the login failed
|
||||
* @throws IllegalArgumentException if the filename or fileType is blank (null, empty or whitespace), or the
|
||||
* fileType is invalid
|
||||
* @throws IOException if we failed to read the file
|
||||
* @see #importJobs(InputStream, String)
|
||||
* @see #importJobs(String, FileType, RundeckJobsImportMethod)
|
||||
*/
|
||||
public RundeckJobsImportResult importJobs(String filename, String fileType) throws RundeckApiException,
|
||||
RundeckApiLoginException, IllegalArgumentException, IOException {
|
||||
AssertUtil.notBlank(fileType, "fileType is mandatory to import jobs !");
|
||||
return importJobs(filename, FileType.valueOf(StringUtils.upperCase(fileType)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Import the definitions of jobs, from the given file
|
||||
*
|
||||
* @param filename of the file containing the jobs definitions - mandatory
|
||||
* @param fileType type of the file. See {@link FileType} - mandatory
|
||||
* @return a {@link RundeckJobsImportResult} instance - won't be null
|
||||
* @throws RundeckApiException in case of error when calling the API
|
||||
* @throws RundeckApiLoginException if the login failed
|
||||
* @throws IllegalArgumentException if the filename is blank (null, empty or whitespace), or the fileType is null
|
||||
* @throws IOException if we failed to read the file
|
||||
* @see #importJobs(InputStream, FileType)
|
||||
* @see #importJobs(String, FileType, RundeckJobsImportMethod)
|
||||
*/
|
||||
public RundeckJobsImportResult importJobs(String filename, FileType fileType) throws RundeckApiException,
|
||||
RundeckApiLoginException, IllegalArgumentException, IOException {
|
||||
return importJobs(filename, fileType, (RundeckJobsImportMethod) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Import the definitions of jobs, from the given file, using the given behavior
|
||||
*
|
||||
* @param filename of the file containing the jobs definitions - mandatory
|
||||
* @param fileType type of the file. See {@link FileType} - mandatory
|
||||
* @param importBehavior see {@link RundeckJobsImportMethod}
|
||||
* @return a {@link RundeckJobsImportResult} instance - won't be null
|
||||
* @throws RundeckApiException in case of error when calling the API
|
||||
* @throws RundeckApiLoginException if the login failed
|
||||
* @throws IllegalArgumentException if the filename or fileType is blank (null, empty or whitespace), or the
|
||||
* fileType or behavior is not valid
|
||||
* @throws IOException if we failed to read the file
|
||||
* @see #importJobs(InputStream, String, String)
|
||||
* @see #importJobs(String, FileType, RundeckJobsImportMethod)
|
||||
*/
|
||||
public RundeckJobsImportResult importJobs(String filename, String fileType, String importBehavior)
|
||||
throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException, IOException {
|
||||
AssertUtil.notBlank(fileType, "fileType is mandatory to import jobs !");
|
||||
return importJobs(filename,
|
||||
FileType.valueOf(StringUtils.upperCase(fileType)),
|
||||
RundeckJobsImportMethod.valueOf(StringUtils.upperCase(importBehavior)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Import the definitions of jobs, from the given file, using the given behavior
|
||||
*
|
||||
* @param filename of the file containing the jobs definitions - mandatory
|
||||
* @param fileType type of the file. See {@link FileType} - mandatory
|
||||
* @param importBehavior see {@link RundeckJobsImportMethod}
|
||||
* @return a {@link RundeckJobsImportResult} instance - won't be null
|
||||
* @throws RundeckApiException in case of error when calling the API
|
||||
* @throws RundeckApiLoginException if the login failed
|
||||
* @throws IllegalArgumentException if the filename is blank (null, empty or whitespace), or the fileType is null
|
||||
* @throws IOException if we failed to read the file
|
||||
* @see #importJobs(InputStream, FileType, RundeckJobsImportMethod)
|
||||
*/
|
||||
public RundeckJobsImportResult importJobs(String filename, FileType fileType, RundeckJobsImportMethod importBehavior)
|
||||
throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException, IOException {
|
||||
AssertUtil.notBlank(filename, "filename (of jobs file) is mandatory to import jobs !");
|
||||
FileInputStream stream = null;
|
||||
try {
|
||||
stream = FileUtils.openInputStream(new File(filename));
|
||||
return importJobs(stream, fileType, importBehavior);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(stream);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Import the definitions of jobs, from the given input stream
|
||||
*
|
||||
* @param stream inputStream for reading the definitions - mandatory
|
||||
* @param fileType type of the file. See {@link FileType} - mandatory
|
||||
* @return a {@link RundeckJobsImportResult} instance - won't be null
|
||||
* @throws RundeckApiException in case of error when calling the API
|
||||
* @throws RundeckApiLoginException if the login failed
|
||||
* @throws IllegalArgumentException if the stream is null, or the fileType is blank (null, empty or whitespace) or
|
||||
* invalid
|
||||
* @see #importJobs(String, String)
|
||||
* @see #importJobs(InputStream, FileType, RundeckJobsImportMethod)
|
||||
*/
|
||||
public RundeckJobsImportResult importJobs(InputStream stream, String fileType) throws RundeckApiException,
|
||||
RundeckApiLoginException, IllegalArgumentException {
|
||||
AssertUtil.notBlank(fileType, "fileType is mandatory to import jobs !");
|
||||
return importJobs(stream, FileType.valueOf(StringUtils.upperCase(fileType)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Import the definitions of jobs, from the given input stream
|
||||
*
|
||||
* @param stream inputStream for reading the definitions - mandatory
|
||||
* @param fileType type of the file. See {@link FileType} - mandatory
|
||||
* @return a {@link RundeckJobsImportResult} instance - won't be null
|
||||
* @throws RundeckApiException in case of error when calling the API
|
||||
* @throws RundeckApiLoginException if the login failed
|
||||
* @throws IllegalArgumentException if the stream or fileType is null
|
||||
* @see #importJobs(String, FileType)
|
||||
* @see #importJobs(InputStream, FileType, RundeckJobsImportMethod)
|
||||
*/
|
||||
public RundeckJobsImportResult importJobs(InputStream stream, FileType fileType) throws RundeckApiException,
|
||||
RundeckApiLoginException, IllegalArgumentException {
|
||||
return importJobs(stream, fileType, (RundeckJobsImportMethod) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Import the definitions of jobs, from the given input stream, using the given behavior
|
||||
*
|
||||
* @param stream inputStream for reading the definitions - mandatory
|
||||
* @param fileType type of the file. See {@link FileType} - mandatory
|
||||
* @param importBehavior see {@link RundeckJobsImportMethod}
|
||||
* @return a {@link RundeckJobsImportResult} instance - won't be null
|
||||
* @throws RundeckApiException in case of error when calling the API
|
||||
* @throws RundeckApiLoginException if the login failed
|
||||
* @throws IllegalArgumentException if the stream is null, or the fileType is blank (null, empty or whitespace), or
|
||||
* the fileType or behavior is not valid
|
||||
* @see #importJobs(String, String, String)
|
||||
* @see #importJobs(InputStream, FileType, RundeckJobsImportMethod)
|
||||
*/
|
||||
public RundeckJobsImportResult importJobs(InputStream stream, String fileType, String importBehavior)
|
||||
throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
|
||||
AssertUtil.notBlank(fileType, "fileType is mandatory to import jobs !");
|
||||
return importJobs(stream,
|
||||
FileType.valueOf(StringUtils.upperCase(fileType)),
|
||||
RundeckJobsImportMethod.valueOf(StringUtils.upperCase(importBehavior)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Import the definitions of jobs, from the given input stream, using the given behavior
|
||||
*
|
||||
* @param stream inputStream for reading the definitions - mandatory
|
||||
* @param fileType type of the file. See {@link FileType} - mandatory
|
||||
* @param importBehavior see {@link RundeckJobsImportMethod}
|
||||
* @return a {@link RundeckJobsImportResult} instance - won't be null
|
||||
* @throws RundeckApiException in case of error when calling the API
|
||||
* @throws RundeckApiLoginException if the login failed
|
||||
* @throws IllegalArgumentException if the stream or fileType is null
|
||||
* @see #importJobs(String, FileType, RundeckJobsImportMethod)
|
||||
*/
|
||||
public RundeckJobsImportResult importJobs(InputStream stream, FileType fileType,
|
||||
RundeckJobsImportMethod importBehavior) throws RundeckApiException, RundeckApiLoginException,
|
||||
IllegalArgumentException {
|
||||
AssertUtil.notNull(stream, "inputStream of jobs is mandatory to import jobs !");
|
||||
AssertUtil.notNull(fileType, "fileType is mandatory to import jobs !");
|
||||
return new ApiCall(this).post(new ApiPathBuilder("/jobs/import").param("format", fileType)
|
||||
.param("dupeOption", importBehavior)
|
||||
.attach("xmlBatch", stream),
|
||||
new JobsImportResultParser("result"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a job, identified by its project, group and name. Note that the groupPath is optional, as a job does not
|
||||
* need to belong to a group (either pass null, or an empty string).
|
||||
|
@ -851,8 +1022,7 @@ public class RundeckClient implements Serializable {
|
|||
public List<RundeckExecution> getJobExecutions(String jobId, ExecutionStatus status, Long max, Long offset)
|
||||
throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
|
||||
AssertUtil.notBlank(jobId, "jobId is mandatory to get the executions of a job !");
|
||||
return new ApiCall(this).get(new ApiPathBuilder("/job/", jobId, "/executions").param("status",
|
||||
status != null ? StringUtils.lowerCase(status.toString()) : null)
|
||||
return new ApiCall(this).get(new ApiPathBuilder("/job/", jobId, "/executions").param("status", status)
|
||||
.param("max", max)
|
||||
.param("offset", offset),
|
||||
new ListParser<RundeckExecution>(new ExecutionParser(),
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright 2011 Vincent Behar
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.rundeck.api.domain;
|
||||
|
||||
/**
|
||||
* The behavior when importing jobs (which may already exist).
|
||||
*
|
||||
* @author Vincent Behar
|
||||
*/
|
||||
public enum RundeckJobsImportMethod {
|
||||
CREATE, UPDATE, SKIP;
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright 2011 Vincent Behar
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.rundeck.api.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Result of importing some jobs into RunDeck
|
||||
*
|
||||
* @author Vincent Behar
|
||||
*/
|
||||
public class RundeckJobsImportResult implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final List<RundeckJob> succeededJobs = new ArrayList<RundeckJob>();
|
||||
|
||||
private final List<RundeckJob> skippedJobs = new ArrayList<RundeckJob>();
|
||||
|
||||
private final Map<RundeckJob, String> failedJobs = new HashMap<RundeckJob, String>();
|
||||
|
||||
public void addSucceededJob(RundeckJob job) {
|
||||
succeededJobs.add(job);
|
||||
}
|
||||
|
||||
public void addSkippedJob(RundeckJob job) {
|
||||
skippedJobs.add(job);
|
||||
}
|
||||
|
||||
public void addFailedJob(RundeckJob job, String errorMessage) {
|
||||
failedJobs.put(job, errorMessage);
|
||||
}
|
||||
|
||||
public List<RundeckJob> getSucceededJobs() {
|
||||
return succeededJobs;
|
||||
}
|
||||
|
||||
public List<RundeckJob> getSkippedJobs() {
|
||||
return skippedJobs;
|
||||
}
|
||||
|
||||
public Map<RundeckJob, String> getFailedJobs() {
|
||||
return failedJobs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RundeckJobsImportResult [succeededJobs=" + succeededJobs + ", skippedJobs=" + skippedJobs
|
||||
+ ", failedJobs=" + failedJobs + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((failedJobs == null) ? 0 : failedJobs.hashCode());
|
||||
result = prime * result + ((skippedJobs == null) ? 0 : skippedJobs.hashCode());
|
||||
result = prime * result + ((succeededJobs == null) ? 0 : succeededJobs.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
RundeckJobsImportResult other = (RundeckJobsImportResult) obj;
|
||||
if (failedJobs == null) {
|
||||
if (other.failedJobs != null)
|
||||
return false;
|
||||
} else if (!failedJobs.equals(other.failedJobs))
|
||||
return false;
|
||||
if (skippedJobs == null) {
|
||||
if (other.skippedJobs != null)
|
||||
return false;
|
||||
} else if (!skippedJobs.equals(other.skippedJobs))
|
||||
return false;
|
||||
if (succeededJobs == null) {
|
||||
if (other.succeededJobs != null)
|
||||
return false;
|
||||
} else if (!succeededJobs.equals(other.succeededJobs))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright 2011 Vincent Behar
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.rundeck.api.parser;
|
||||
|
||||
import java.util.List;
|
||||
import org.dom4j.Node;
|
||||
import org.rundeck.api.domain.RundeckJob;
|
||||
import org.rundeck.api.domain.RundeckJobsImportResult;
|
||||
|
||||
/**
|
||||
* Parser for a single {@link RundeckJobsImportResult}
|
||||
*
|
||||
* @author Vincent Behar
|
||||
*/
|
||||
public class JobsImportResultParser implements XmlNodeParser<RundeckJobsImportResult> {
|
||||
|
||||
private String xpath;
|
||||
|
||||
public JobsImportResultParser() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param xpath of the result element if it is not the root node
|
||||
*/
|
||||
public JobsImportResultParser(String xpath) {
|
||||
super();
|
||||
this.xpath = xpath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RundeckJobsImportResult parseXmlNode(Node node) {
|
||||
Node resultNode = xpath != null ? node.selectSingleNode(xpath) : node;
|
||||
|
||||
RundeckJobsImportResult result = new RundeckJobsImportResult();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Node> succeededJobsNodes = resultNode.selectNodes("succeeded/job");
|
||||
if (succeededJobsNodes != null) {
|
||||
for (Node succeededJobNode : succeededJobsNodes) {
|
||||
RundeckJob job = new JobParser().parseXmlNode(succeededJobNode);
|
||||
result.addSucceededJob(job);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Node> skippedJobsNodes = resultNode.selectNodes("skipped/job");
|
||||
if (skippedJobsNodes != null) {
|
||||
for (Node skippedJobNode : skippedJobsNodes) {
|
||||
RundeckJob job = new JobParser().parseXmlNode(skippedJobNode);
|
||||
result.addSkippedJob(job);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Node> failedJobsNodes = resultNode.selectNodes("failed/job");
|
||||
if (failedJobsNodes != null) {
|
||||
for (Node failedJobNode : failedJobsNodes) {
|
||||
RundeckJob job = new JobParser().parseXmlNode(failedJobNode);
|
||||
result.addFailedJob(job, failedJobNode.valueOf("error"));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
|
@ -85,6 +85,16 @@ rundeck.exportJobsToFile("/tmp/jobs.xml", "my-project")
|
|||
rundeck.exportJobToFile("/tmp/job.xml", "job-id")
|
||||
{code}
|
||||
|
||||
h2. Importing jobs
|
||||
|
||||
{code}
|
||||
import org.rundeck.api.RundeckClient
|
||||
rundeck = new RundeckClient("http://localhost:4440", "admin", "admin")
|
||||
|
||||
result = rundeck.importJobs("/tmp/jobs.xml", "xml")
|
||||
println "${result.succeededJobs.size} jobs successfully imported, ${result.skippedJobs.size} jobs skipped, and ${result.failedJobs.size} jobs failed"
|
||||
{code}
|
||||
|
||||
h2. And more...
|
||||
|
||||
See the API documentation of the [RundeckClient|./apidocs/org/rundeck/api/RundeckClient.html] class for more interactions with your RunDeck instance...
|
||||
|
|
|
@ -90,6 +90,16 @@ rundeck.exportJobsToFile("/tmp/jobs.xml", "my-project")
|
|||
rundeck.exportJobToFile("/tmp/job.xml", "job-id")
|
||||
{code}
|
||||
|
||||
h2. Importing jobs
|
||||
|
||||
{code}
|
||||
import org.rundeck.api.RundeckClient
|
||||
rundeck = RundeckClient.new("http://localhost:4440", "admin", "admin")
|
||||
|
||||
result = rundeck.importJobs("/tmp/jobs.xml", "xml")
|
||||
puts "#{result.succeededJobs.size} jobs successfully imported, #{result.skippedJobs.size} jobs skipped, and #{result.failedJobs.size} jobs failed"
|
||||
{code}
|
||||
|
||||
h2. And more...
|
||||
|
||||
See the API documentation of the [RundeckClient|./apidocs/org/rundeck/api/RundeckClient.html] class for more interactions with your RunDeck instance...
|
||||
|
|
|
@ -74,6 +74,16 @@ rundeck.exportJobsToFile("/tmp/jobs.xml", "my-project")
|
|||
rundeck.exportJobToFile("/tmp/job.xml", "job-id")
|
||||
{code}
|
||||
|
||||
h2. Importing jobs
|
||||
|
||||
{code}
|
||||
from org.rundeck.api import RundeckClient
|
||||
rundeck = RundeckClient("http://localhost:4440", "admin", "admin")
|
||||
|
||||
result = rundeck.importJobs("/tmp/jobs.xml", "xml")
|
||||
print("%s jobs successfully imported, %s jobs skipped, and %s jobs failed" % (result.succeededJobs.size, result.skippedJobs.size, result.failedJobs.size))
|
||||
{code}
|
||||
|
||||
h2. And more...
|
||||
|
||||
See the API documentation of the [RundeckClient|./apidocs/org/rundeck/api/RundeckClient.html] class for more interactions with your RunDeck instance...
|
||||
|
|
|
@ -10,7 +10,7 @@ h2. RunDeck API version 1
|
|||
* Listing Jobs - OK
|
||||
* Running a Job - OK
|
||||
* Exporting Jobs - OK (XML only, YAML not supported yet)
|
||||
* Importing Jobs - *TODO*
|
||||
* Importing Jobs - OK
|
||||
* Getting a Job Definition - OK (XML only, YAML not supported yet)
|
||||
* Deleting a Job Definition - OK
|
||||
* Getting Executions for a Job - OK
|
||||
|
|
|
@ -36,6 +36,30 @@
|
|||
</ul>
|
||||
</answer>
|
||||
</faq>
|
||||
|
||||
</part>
|
||||
|
||||
<part id="http">
|
||||
<title>HTTP connections to RunDeck</title>
|
||||
|
||||
<faq id="ssl">
|
||||
<question>
|
||||
What about SSL (HTTPS) ?
|
||||
</question>
|
||||
<answer>
|
||||
<p>The lib will trust any certificate when connecting to a RunDeck instance running on HTTPS (even self-signed certificates).</p>
|
||||
</answer>
|
||||
</faq>
|
||||
|
||||
<faq id="proxy">
|
||||
<question>
|
||||
How do I use a proxy ?
|
||||
</question>
|
||||
<answer>
|
||||
<p>See <a href="http://download.oracle.com/javase/6/docs/technotes/guides/net/proxies.html">the Java doc on proxies</a>. You will need a JAVA_OPTS env variable with a value like "-Dhttp.proxyHost=localhost -Dhttp.proxyPort=8888".</p>
|
||||
</answer>
|
||||
</faq>
|
||||
|
||||
</part>
|
||||
|
||||
</faqs>
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright 2011 Vincent Behar
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.rundeck.api.parser;
|
||||
|
||||
import java.io.InputStream;
|
||||
import org.dom4j.Document;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.rundeck.api.domain.RundeckJob;
|
||||
import org.rundeck.api.domain.RundeckJobsImportResult;
|
||||
|
||||
/**
|
||||
* Test the {@link JobsImportResultParser}
|
||||
*
|
||||
* @author Vincent Behar
|
||||
*/
|
||||
public class JobsImportResultParserTest {
|
||||
|
||||
@Test
|
||||
public void parseResult() throws Exception {
|
||||
InputStream input = getClass().getResourceAsStream("jobs-import.xml");
|
||||
Document document = ParserHelper.loadDocument(input);
|
||||
|
||||
RundeckJobsImportResult result = new JobsImportResultParser("result").parseXmlNode(document);
|
||||
|
||||
Assert.assertEquals(2, result.getSucceededJobs().size());
|
||||
Assert.assertEquals(0, result.getSkippedJobs().size());
|
||||
Assert.assertEquals(1, result.getFailedJobs().size());
|
||||
|
||||
Assert.assertEquals("job-one", result.getSucceededJobs().get(0).getName());
|
||||
Assert.assertEquals("job-two", result.getSucceededJobs().get(1).getName());
|
||||
|
||||
RundeckJob failedJob = result.getFailedJobs().keySet().iterator().next();
|
||||
Assert.assertEquals("job-three", failedJob.getName());
|
||||
Assert.assertEquals("Error message", result.getFailedJobs().get(failedJob));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<result success='true' apiversion='1'><succeeded count='2'><job index='1'><id>1</id><name>job-one</name><group>import</group><project>test</project><url>/job/show/1</url></job><job index='2'><id>2</id><name>job-two</name><group>import</group><project>test</project><url>/job/show/2</url></job></succeeded><failed count='1'><job index='3'><name>job-three</name><group>import</group><project>test</project><error>Error message</error></job></failed><skipped count='0'></skipped></result>
|
Loading…
Add table
Add a link
Reference in a new issue