From bea99b1c97157595be8c395ba74487451798abc3 Mon Sep 17 00:00:00 2001 From: Greg Schueler Date: Fri, 7 Mar 2014 13:22:59 -0800 Subject: [PATCH] Add project export for apiv11 --- .../java/org/rundeck/api/RundeckClient.java | 49 +++++++++++++++++-- .../org/rundeck/api/RundeckClientTest.java | 10 ++++ .../betamax/tapes/export_projectv11.yaml | 23 +++++++++ 3 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 src/test/resources/betamax/tapes/export_projectv11.yaml diff --git a/src/main/java/org/rundeck/api/RundeckClient.java b/src/main/java/org/rundeck/api/RundeckClient.java index 1888684..bfca253 100644 --- a/src/main/java/org/rundeck/api/RundeckClient.java +++ b/src/main/java/org/rundeck/api/RundeckClient.java @@ -34,11 +34,7 @@ import org.rundeck.api.util.AssertUtil; import org.rundeck.api.util.PagedResults; import org.rundeck.api.util.ParametersUtil; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; +import java.io.*; import java.util.*; import java.util.concurrent.TimeUnit; @@ -378,6 +374,49 @@ public class RundeckClient implements Serializable { AssertUtil.notBlank(projectName, "projectName is mandatory to create a project !"); new ApiCall(this).delete(new ApiPathBuilder("/project/", projectName)); } + /** + * Convenience method to export the archive of a project to the specified file. + * + * @param projectName name of the project - mandatory + * @param out file to write to + * @return number of bytes written to the stream + * + * @throws RundeckApiException in case of error when calling the API (non-existent project with this name) + * @throws RundeckApiLoginException if the login fails (in case of login-based authentication) + * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication) + * @throws IllegalArgumentException if the projectName is blank (null, empty or whitespace) + */ + public int exportProject(final String projectName, final File out) throws + RundeckApiException, RundeckApiLoginException, + RundeckApiTokenException, IllegalArgumentException, IOException { + final FileOutputStream fileOutputStream = new FileOutputStream(out); + try { + return exportProject(projectName, fileOutputStream); + }finally { + fileOutputStream.close(); + } + } + /** + * Export the archive of a project to the specified outputstream + * + * @param projectName name of the project - mandatory + * @return number of bytes written to the stream + * + * @throws RundeckApiException in case of error when calling the API (non-existent project with this name) + * @throws RundeckApiLoginException if the login fails (in case of login-based authentication) + * @throws RundeckApiTokenException if the token is invalid (in case of token-based authentication) + * @throws IllegalArgumentException if the projectName is blank (null, empty or whitespace) + */ + public int exportProject(String projectName, OutputStream out) throws + RundeckApiException, RundeckApiLoginException, + RundeckApiTokenException, IllegalArgumentException, IOException { + + AssertUtil.notBlank(projectName, "projectName is mandatory to export a project archive!"); + return new ApiCall(this).get( + new ApiPathBuilder("/project/", projectName, "/export") + .accept("application/zip"), + out); + } /** * Return the configuration of a project * diff --git a/src/test/java/org/rundeck/api/RundeckClientTest.java b/src/test/java/org/rundeck/api/RundeckClientTest.java index 4396061..1b93bfa 100644 --- a/src/test/java/org/rundeck/api/RundeckClientTest.java +++ b/src/test/java/org/rundeck/api/RundeckClientTest.java @@ -28,6 +28,7 @@ import org.rundeck.api.query.ExecutionQuery; import org.rundeck.api.util.PagedResults; import java.io.ByteArrayInputStream; +import java.io.File; import java.io.InputStream; import java.util.*; @@ -160,6 +161,15 @@ public class RundeckClientTest { Assert.assertNull(value); } @Test + @Betamax(tape = "export_projectv11") + public void exportProject() throws Exception { + RundeckClient client1 = createClient(TEST_TOKEN_6, 11); + File temp = File.createTempFile("test-archive", ".zip"); + temp.deleteOnExit(); + int i = client1.exportProject("DEF1", temp); + Assert.assertEquals(8705,i); + } + @Test @Betamax(tape = "get_history") public void getHistory() throws Exception { final RundeckHistory test = client.getHistory("test"); diff --git a/src/test/resources/betamax/tapes/export_projectv11.yaml b/src/test/resources/betamax/tapes/export_projectv11.yaml new file mode 100644 index 0000000..595c78d --- /dev/null +++ b/src/test/resources/betamax/tapes/export_projectv11.yaml @@ -0,0 +1,23 @@ +!tape +name: export_projectv11 +interactions: +- recorded: 2014-03-07T21:12:45.024Z + request: + method: GET + uri: http://rundeck.local:4440/api/11/project/DEF1/export + headers: + Accept: application/zip + Host: rundeck.local:4440 + Proxy-Connection: Keep-Alive + User-Agent: RunDeck API Java Client 11 + X-RunDeck-Auth-Token: Do4d3NUD5DKk21DR4sNK755RcPk618vn + response: + status: 200 + headers: + Content-Disposition: attachment; filename="DEF1-20140307-131244.rdproject.jar" + Content-Type: application/zip + Expires: Thu, 01 Jan 1970 00:00:00 GMT + Server: Jetty(7.6.0.v20120127) + Set-Cookie: JSESSIONID=18wgn0qj6x6ho1vpkwj2logftl;Path=/ + body: !!binary |- + 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NDlhYy1hYmYyLTRkZTdlYzc1ODcyZi54bWxQSwECFAAUAAgICACWaWdENmV0rRoBAAAoAgAAPgAAAAAAAAAAAAAAAACqAwAAcnVuZGVjay1ERUYxL2pvYnMvam9iLTA5NGIwZGNjLWVkNzUtNDE1Zi04NDA5LTMxZTZiMjFiNTAyZC54bWxQSwECFAAUAAgICACWaWdEoSpLBSYBAACbAgAAPgAAAAAAAAAAAAAAAAAwBQAAcnVuZGVjay1ERUYxL2pvYnMvam9iLTJiZTk2NmU3LTQ0MGUtNDg5Ny04YTU5LTZhZDEyNmRmNjAzZS54bWxQSwECFAAUAAgICACWaWdE4FnkVG4BAAAcAwAAPgAAAAAAAAAAAAAAAADCBgAAcnVuZGVjay1ERUYxL2pvYnMvam9iLWU2ZjYxYWUyLWFlZTEtNDYxMC05ZmU5LThjNmRmMmNlOGRiYy54bWxQSwECFAAUAAgICACWaWdE0201rJEBAACJAwAAPgAAAAAAAAAAAAAAAACcCAAAcnVuZGVjay1ERUYxL2pvYnMvam9iLTNmNjg1M2Y4LWI1ODktNGRhOC1iYTc2LTE2MzZlZjgxMWNlNi54bWxQSwECFAAUAAgICACWaWdE9sg0SZEBAACJAwAAPgAAAAAAAAAAAAAAAACZCgAAcnVuZGVjay1ERUYxL2pvYnMvam9iLWFjNzhkZmJiLWE0OWMtNDBhYi1hY2Q5LTk0MDhiZTU2MWU3NC54bWxQSwECFAAUAAgICACWaWdEs3XyZB0CAACGBQAAPgAAAAAAAAAAAAAAAACWDAAAcnVuZGVjay1ERUYxL2pvYnMvam9iLTc1NmM5OWY3LTA0ZmItNDM4Yy04NGY1LTE3MjJkOTY3ZDFjYi54bWxQSwECFAAUAAgICACWaWdEg9BA1bgBAADXAwAAPgAAAAAAAAAAAAAAAAAfDwAAcnVuZGVjay1ERUYxL2pvYnMvam9iLTNhZWM3ZGZiLTk1MDItNDg3Ni04NzYzLTFhYTc4OGM4ZmM5Yy54bWxQSwECFAAUAAgICACWaWdE8UF0QDUBAABpAgAAPgAAAAAAAAAAAAAAAABDEQAAcnVuZGVjay1ERUYxL2pvYnMvam9iLTg1OTZjYjljLTY4MzMtNDNmNy1hMGY3LTQ2NjNkZDhhYmMyOS54bWxQSwECFAAUAAgICACWaWdEdesbFksBAAC+AgAAPgAAAAAAAAAAAAAAAADkEgAAcnVuZGVjay1ERUYxL2pvYnMvam9iLWQ0MDIzYTcyLTU0ZTEtNDFiNS1iNGQ0LTRkZDdlNWQ0ZjVlNC54bWxQSwECFAAUAAgICACWaWdEAAAAAAIAAAAAAAAAGAAAAAAAAAAAAAAAAACbFAAAcnVuZGVjay1ERUYxL2V4ZWN1dGlvbnMvUEsBAhQAFAAICAgAlmlnRC1zICneAQAADgQAACoAAAAAAAAAAAAAAAAA4xQAAHJ1bmRlY2stREVGMS9leGVjdXRpb25zL2V4ZWN1dGlvbi0xNDU3LnhtbFBLAQIUABQACAgIAJZpZ0RkWJKhlgAAAKcBAAApAAAAAAAAAAAAAAAAABkXAABydW5kZWNrLURFRjEvZXhlY3V0aW9ucy9vdXRwdXQtMTQ1Ny5yZGxvZ1BLAQIUABQACAgIAJZpZ0QFJ/wt3gAAAJYCAAAtAAAAAAAAAAAAAAAAAAYYAABydW5kZWNrLURFRjEvZXhlY3V0aW9ucy9zdGF0ZS0xNDU3LnN0YXRlLmpzb25QSwECFAAUAAgICACWaWdEAAAAAAIAAAAAAAAAFQAAAAAAAAAAAAAAAAA/GQAAcnVuZGVjay1ERUYxL3JlcG9ydHMvUEsBAhQAFAAICAgAlmlnRGn21Ec3AQAANQIAACQAAAAAAAAAAAAAAAAAhBkAAHJ1bmRlY2stREVGMS9yZXBvcnRzL3JlcG9ydC0xNDc0LnhtbFBLBQYAAAAAEwATAN4GAAANGwAAAAA=