mirror of
https://github.com/Fishwaldo/rundeck-api-java-client.git
synced 2025-07-10 15:08:19 +00:00
add support for exporting jobs (to file)
This commit is contained in:
parent
64e0c346d3
commit
1594773a79
4 changed files with 131 additions and 33 deletions
5
pom.xml
5
pom.xml
|
@ -397,6 +397,11 @@
|
||||||
<artifactId>commons-lang</artifactId>
|
<artifactId>commons-lang</artifactId>
|
||||||
<version>2.6</version>
|
<version>2.6</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-io</groupId>
|
||||||
|
<artifactId>commons-io</artifactId>
|
||||||
|
<version>2.0.1</version>
|
||||||
|
</dependency>
|
||||||
<!-- XML Parsing -->
|
<!-- XML Parsing -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>dom4j</groupId>
|
<groupId>dom4j</groupId>
|
||||||
|
|
|
@ -15,7 +15,9 @@
|
||||||
*/
|
*/
|
||||||
package org.rundeck.api;
|
package org.rundeck.api;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.security.KeyManagementException;
|
import java.security.KeyManagementException;
|
||||||
import java.security.KeyStoreException;
|
import java.security.KeyStoreException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
@ -117,6 +119,25 @@ class ApiCall {
|
||||||
return execute(new HttpGet(client.getUrl() + RundeckClient.API_ENDPOINT + apiPath), parser);
|
return execute(new HttpGet(client.getUrl() + RundeckClient.API_ENDPOINT + apiPath), parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute an HTTP GET request to the RunDeck instance, on the given path. We will login first, and then execute the
|
||||||
|
* API call.
|
||||||
|
*
|
||||||
|
* @param apiPath on which we will make the HTTP request - see {@link ApiPathBuilder}
|
||||||
|
* @return a new {@link InputStream} instance, not linked with network resources
|
||||||
|
* @throws RundeckApiException in case of error when calling the API
|
||||||
|
* @throws RundeckApiLoginException if the login fails
|
||||||
|
*/
|
||||||
|
public InputStream get(ApiPathBuilder apiPath) throws RundeckApiException, RundeckApiLoginException {
|
||||||
|
ByteArrayInputStream response = execute(new HttpGet(client.getUrl() + RundeckClient.API_ENDPOINT + apiPath));
|
||||||
|
|
||||||
|
// try to load the document, to throw an exception in case of error
|
||||||
|
ParserHelper.loadDocument(response);
|
||||||
|
response.reset();
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute an HTTP DELETE request to the RunDeck instance, on the given path. We will login first, and then execute
|
* 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.
|
* the API call. At the end, the given parser will be used to convert the response to a more useful result object.
|
||||||
|
@ -144,6 +165,23 @@ class ApiCall {
|
||||||
*/
|
*/
|
||||||
private <T> T execute(HttpRequestBase request, XmlNodeParser<T> parser) throws RundeckApiException,
|
private <T> T execute(HttpRequestBase request, XmlNodeParser<T> parser) throws RundeckApiException,
|
||||||
RundeckApiLoginException {
|
RundeckApiLoginException {
|
||||||
|
// execute the request
|
||||||
|
InputStream response = execute(request);
|
||||||
|
|
||||||
|
// read and parse the response
|
||||||
|
Document xmlDocument = ParserHelper.loadDocument(response);
|
||||||
|
return parser.parseXmlNode(xmlDocument);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute an HTTP request to the RunDeck instance. We will login first, and then execute the API call.
|
||||||
|
*
|
||||||
|
* @param request to execute. see {@link HttpGet}, {@link HttpDelete}, and so on...
|
||||||
|
* @return a new {@link InputStream} instance, not linked with network resources
|
||||||
|
* @throws RundeckApiException in case of error when calling the API
|
||||||
|
* @throws RundeckApiLoginException if the login fails
|
||||||
|
*/
|
||||||
|
private ByteArrayInputStream execute(HttpRequestBase request) throws RundeckApiException, RundeckApiLoginException {
|
||||||
HttpClient httpClient = instantiateHttpClient();
|
HttpClient httpClient = instantiateHttpClient();
|
||||||
try {
|
try {
|
||||||
login(httpClient);
|
login(httpClient);
|
||||||
|
@ -176,6 +214,7 @@ class ApiCall {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check the response code (should be 2xx, even in case of error : error message is in the XML result)
|
||||||
if (response.getStatusLine().getStatusCode() / 100 != 2) {
|
if (response.getStatusLine().getStatusCode() / 100 != 2) {
|
||||||
throw new RundeckApiException("Invalid HTTP response '" + response.getStatusLine() + "' for "
|
throw new RundeckApiException("Invalid HTTP response '" + response.getStatusLine() + "' for "
|
||||||
+ request.getURI());
|
+ request.getURI());
|
||||||
|
@ -185,17 +224,12 @@ class ApiCall {
|
||||||
+ response.getStatusLine());
|
+ response.getStatusLine());
|
||||||
}
|
}
|
||||||
|
|
||||||
// read and parse the response
|
// return a new inputStream, so that we can close all network resources
|
||||||
Document xmlDocument = ParserHelper.loadDocument(response);
|
|
||||||
T result = parser.parseXmlNode(xmlDocument);
|
|
||||||
|
|
||||||
// release the connection
|
|
||||||
try {
|
try {
|
||||||
EntityUtils.consume(response.getEntity());
|
return new ByteArrayInputStream(EntityUtils.toByteArray(response.getEntity()));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RundeckApiException("Failed to consume entity (release connection)", e);
|
throw new RundeckApiException("Failed to consume entity and convert the inputStream", e);
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
} finally {
|
} finally {
|
||||||
httpClient.getConnectionManager().shutdown();
|
httpClient.getConnectionManager().shutdown();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,16 @@
|
||||||
*/
|
*/
|
||||||
package org.rundeck.api;
|
package org.rundeck.api;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.rundeck.api.RundeckApiException.RundeckApiLoginException;
|
import org.rundeck.api.RundeckApiException.RundeckApiLoginException;
|
||||||
import org.rundeck.api.domain.RundeckAbort;
|
import org.rundeck.api.domain.RundeckAbort;
|
||||||
|
@ -195,6 +200,85 @@ public class RundeckClient implements Serializable {
|
||||||
new ListParser<RundeckJob>(new JobParser(), "result/jobs/job"));
|
new ListParser<RundeckJob>(new JobParser(), "result/jobs/job"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export the definitions of all jobs that belongs to the given project, as an XML file
|
||||||
|
*
|
||||||
|
* @param filename path of the file where the content should be saved
|
||||||
|
* @param project name of the project - mandatory
|
||||||
|
* @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
|
||||||
|
* @throws RundeckApiLoginException if the login failed
|
||||||
|
* @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
|
||||||
|
* @throws IOException if we failed to write to the file
|
||||||
|
* @see #exportJobsToFile(String, String, String, String, String...)
|
||||||
|
* @see #exportJobs(String)
|
||||||
|
*/
|
||||||
|
public void exportJobsToFile(String filename, String project) throws RundeckApiException, RundeckApiLoginException,
|
||||||
|
IllegalArgumentException, IOException {
|
||||||
|
exportJobsToFile(filename, project, null, null, new String[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export the definitions of the jobs that belongs to the given project, and matches the given criteria (jobFilter,
|
||||||
|
* groupPath and jobIds), as an XML file
|
||||||
|
*
|
||||||
|
* @param filename path of the file where the content should be saved
|
||||||
|
* @param project name of the project - mandatory
|
||||||
|
* @param jobFilter a filter for the job Name - optional
|
||||||
|
* @param groupPath a group or partial group path to include all jobs within that group path - optional
|
||||||
|
* @param jobIds a list of Job IDs to include - optional
|
||||||
|
* @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
|
||||||
|
* @throws RundeckApiLoginException if the login failed
|
||||||
|
* @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
|
||||||
|
* @throws IOException if we failed to write to the file
|
||||||
|
* @see #exportJobsToFile(String, String)
|
||||||
|
* @see #exportJobs(String, String, String, String...)
|
||||||
|
*/
|
||||||
|
public void exportJobsToFile(String filename, String project, String jobFilter, String groupPath, String... jobIds)
|
||||||
|
throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException, IOException {
|
||||||
|
InputStream inputStream = exportJobs(project, jobFilter, groupPath, jobIds);
|
||||||
|
FileUtils.writeByteArrayToFile(new File(filename), IOUtils.toByteArray(inputStream));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export the definitions of all jobs that belongs to the given project
|
||||||
|
*
|
||||||
|
* @param project name of the project - mandatory
|
||||||
|
* @return an {@link InputStream} instance, not linked to any network resources - won't be null
|
||||||
|
* @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
|
||||||
|
* @throws RundeckApiLoginException if the login failed
|
||||||
|
* @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
|
||||||
|
* @see #exportJobs(String, String, String, String...)
|
||||||
|
* @see #exportJobsToFile(String, String)
|
||||||
|
*/
|
||||||
|
public InputStream exportJobs(String project) throws RundeckApiException, RundeckApiLoginException,
|
||||||
|
IllegalArgumentException {
|
||||||
|
return exportJobs(project, null, null, new String[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export the definitions of the jobs that belongs to the given project, and matches the given criteria (jobFilter,
|
||||||
|
* groupPath and jobIds)
|
||||||
|
*
|
||||||
|
* @param project name of the project - mandatory
|
||||||
|
* @param jobFilter a filter for the job Name - optional
|
||||||
|
* @param groupPath a group or partial group path to include all jobs within that group path - optional
|
||||||
|
* @param jobIds a list of Job IDs to include - optional
|
||||||
|
* @return an {@link InputStream} instance, not linked to any network resources - won't be null
|
||||||
|
* @throws RundeckApiException in case of error when calling the API (non-existent project with this name)
|
||||||
|
* @throws RundeckApiLoginException if the login failed
|
||||||
|
* @throws IllegalArgumentException if the project is blank (null, empty or whitespace)
|
||||||
|
* @see #exportJobs(String)
|
||||||
|
* @see #exportJobsToFile(String, String, String, String, String...)
|
||||||
|
*/
|
||||||
|
public InputStream exportJobs(String project, String jobFilter, String groupPath, String... jobIds)
|
||||||
|
throws RundeckApiException, RundeckApiLoginException, IllegalArgumentException {
|
||||||
|
AssertUtil.notBlank(project, "project is mandatory to export all jobs !");
|
||||||
|
return new ApiCall(this).get(new ApiPathBuilder("/jobs/export").param("project", project)
|
||||||
|
.param("jobFilter", jobFilter)
|
||||||
|
.param("groupPath", groupPath)
|
||||||
|
.param("idlist", StringUtils.join(jobIds, ",")));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a job, identified by its project, group and name. Note that the groupPath is optional, as a job does not
|
* 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).
|
* need to belong to a group (either pass null, or an empty string).
|
||||||
|
|
|
@ -15,9 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.rundeck.api.parser;
|
package org.rundeck.api.parser;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import org.apache.http.HttpResponse;
|
|
||||||
import org.dom4j.Document;
|
import org.dom4j.Document;
|
||||||
import org.dom4j.DocumentException;
|
import org.dom4j.DocumentException;
|
||||||
import org.dom4j.Node;
|
import org.dom4j.Node;
|
||||||
|
@ -31,35 +29,12 @@ import org.rundeck.api.RundeckApiException;
|
||||||
*/
|
*/
|
||||||
public class ParserHelper {
|
public class ParserHelper {
|
||||||
|
|
||||||
/**
|
|
||||||
* Load an XML {@link Document} from the given RunDeck {@link HttpResponse}.
|
|
||||||
*
|
|
||||||
* @param httpResponse from an API call to RunDeck
|
|
||||||
* @return an XML {@link Document}
|
|
||||||
* @throws RundeckApiException if we failed to read the response, or if the response is an error
|
|
||||||
* @see #loadDocument(InputStream)
|
|
||||||
*/
|
|
||||||
public static Document loadDocument(HttpResponse httpResponse) throws RundeckApiException {
|
|
||||||
InputStream inputStream = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
inputStream = httpResponse.getEntity().getContent();
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
throw new RundeckApiException("Failed to read RunDeck reponse", e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RundeckApiException("Failed to read RunDeck reponse", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return loadDocument(inputStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load an XML {@link Document} from the given {@link InputStream}
|
* Load an XML {@link Document} from the given {@link InputStream}
|
||||||
*
|
*
|
||||||
* @param inputStream from an API call to RunDeck
|
* @param inputStream from an API call to RunDeck
|
||||||
* @return an XML {@link Document}
|
* @return an XML {@link Document}
|
||||||
* @throws RundeckApiException if we failed to read the response, or if the response is an error
|
* @throws RundeckApiException if we failed to read the response, or if the response is an error
|
||||||
* @see #loadDocument(HttpResponse)
|
|
||||||
*/
|
*/
|
||||||
public static Document loadDocument(InputStream inputStream) throws RundeckApiException {
|
public static Document loadDocument(InputStream inputStream) throws RundeckApiException {
|
||||||
SAXReader reader = new SAXReader();
|
SAXReader reader = new SAXReader();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue