diff --git a/aws/core/src/test/java/org/jclouds/aws/ComputeAndBlobStoreTogetherHappilyLiveTest.java b/aws/core/src/test/java/org/jclouds/aws/ComputeAndBlobStoreTogetherHappilyLiveTest.java index fd941c6456..9d7b37602e 100644 --- a/aws/core/src/test/java/org/jclouds/aws/ComputeAndBlobStoreTogetherHappilyLiveTest.java +++ b/aws/core/src/test/java/org/jclouds/aws/ComputeAndBlobStoreTogetherHappilyLiveTest.java @@ -21,18 +21,23 @@ package org.jclouds.aws; import static org.jclouds.compute.BaseComputeServiceLiveTest.buildScript; import static org.jclouds.compute.options.TemplateOptions.Builder.runScript; -import static org.jclouds.compute.util.ComputeServiceUtils.buildCurlsh; -import static org.jclouds.io.Payloads.newStringPayload; +import static org.jclouds.compute.util.ComputeServiceUtils.execHttpResponse; +import static org.jclouds.compute.util.ComputeServiceUtils.extractTargzIntoDirectory; +import static org.jclouds.scriptbuilder.domain.Statements.newStatementList; + +import java.net.URI; import org.jclouds.aws.ec2.compute.BlobStoreAndComputeServiceLiveTest; +import org.jclouds.blobstore.BlobStore; import org.jclouds.compute.RunNodesException; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.OperatingSystem; -import org.jclouds.compute.options.TemplateOptions; import org.jclouds.http.HttpRequest; +import org.jclouds.scriptbuilder.domain.Statement; import org.testng.annotations.Test; /** + * This test helps us understand how we can use the power of blobstores to our favor. * * @author Adrian Cole */ @@ -57,9 +62,9 @@ public class ComputeAndBlobStoreTogetherHappilyLiveTest extends BlobStoreAndComp * next convert this into something that can be invoked via the commandline. Looking around, it * seems like alestic runurl is pretty close. However, it is limited as it only works on requests * that can be fully specified without headers (ex. Amazon S3). Instead, we use a variant - * (curlsh). + * (execHttpResponse). *
- * curlsh simply assembles an http request, headers and all, and passes it to bash + * execHttpResponse simply assembles an http request, headers and all, and passes it to bash * * With this script ready, any node or nodes will take instructions from the blobstore when it * boots up. we verify this with an assertion. @@ -79,15 +84,27 @@ public class ComputeAndBlobStoreTogetherHappilyLiveTest extends BlobStoreAndComp // configured for amz. Note we are getting temporary access to a private blob. HttpRequest signedRequestOfInstallScript = blobContext.getBlobStore().signRequestForBlob(tag, "openjdk/install"); - // instruct the bootstrap to pull the script from the blobstore and invoke it directly with bash. - TemplateOptions runOpenJDKInstallDirectlyFromBlobStore = runScript(newStringPayload(buildCurlsh(signedRequestOfInstallScript))); + // so one of our commands is to execute the contents of the blob above + Statement installOpenJDK = execHttpResponse(signedRequestOfInstallScript); + + // if we want to, we can mix and match batched and ad-hoc commands, such as extracting maven + String mavenVersion = "3.0-beta-3"; + Statement extractMavenIntoUsrLocal = extractTargzIntoDirectory(URI + .create("http://mirrors.ibiblio.org/pub/mirrors/apache//maven/binaries/apache-maven-" + mavenVersion + + "-bin.tar.gz"), "/usr/local"); + + // have both of these commands occur on boot + Statement bootstrapInstructions = newStatementList(installOpenJDK, extractMavenIntoUsrLocal); // now that we have the correct instructions, kick-off the provisioner - Iterable extends NodeMetadata> nodes = computeContext.getComputeService().runNodesWithTag(tag, 1, - runOpenJDKInstallDirectlyFromBlobStore); + Iterable extends NodeMetadata> nodes = computeContext.getComputeService().runNodesWithTag(tag, 2, + runScript(bootstrapInstructions)); - // ensure the bootstrap operated by checking for a known signature of success. - assertSshOutputOfCommandContains(nodes, "openjdk -version", "OpenJDK"); + // ensure the bootstrap operated by checking for the components we installed at boot time. + // Note this test will ensure both nodes are in sync. + assertSshOutputOfCommandContains(nodes, "java -version", "OpenJDK"); + assertSshOutputOfCommandContains(nodes, "/usr/local/apache-maven-" + mavenVersion + "/bin/mvn -version", + "Apache Maven " + mavenVersion + ""); } } diff --git a/aws/core/src/test/java/org/jclouds/aws/ec2/compute/BlobStoreAndComputeServiceLiveTest.java b/aws/core/src/test/java/org/jclouds/aws/ec2/compute/BlobStoreAndComputeServiceLiveTest.java index e10b353170..4febc492b6 100644 --- a/aws/core/src/test/java/org/jclouds/aws/ec2/compute/BlobStoreAndComputeServiceLiveTest.java +++ b/aws/core/src/test/java/org/jclouds/aws/ec2/compute/BlobStoreAndComputeServiceLiveTest.java @@ -64,25 +64,26 @@ public class BlobStoreAndComputeServiceLiveTest { setupCredentials(); computeContext = new ComputeServiceContextFactory().createContext(computeServiceProvider, identity, credential, ImmutableSet.of(new Log4JLoggingModule(), new JschSshClientModule())); - blobContext = new BlobStoreContextFactory().createContext(blobStoreProvider, identity, credential, - ImmutableSet.of(new Log4JLoggingModule())); + blobContext = new BlobStoreContextFactory().createContext(blobStoreProvider, identity, credential, ImmutableSet + .of(new Log4JLoggingModule())); blobContext.getAsyncBlobStore().createContainerInLocation(null, tag); computeContext.getComputeService().destroyNodesMatching(NodePredicates.withTag(tag)); } protected void assertSshOutputOfCommandContains(Iterable extends NodeMetadata> nodes, String cmd, String expects) { - IPSocket socket = new IPSocket(get(get(nodes, 0).getPublicAddresses(), 0), 22); + for (NodeMetadata node : nodes) { + IPSocket socket = new IPSocket(get(node.getPublicAddresses(), 0), 22); - SshClient ssh = computeContext.utils().sshFactory().create(socket, get(nodes, 0).getCredentials().identity, - get(nodes, 0).getCredentials().credential.getBytes()); - try { - ssh.connect(); - ; - ExecResponse exec = ssh.exec(cmd); - assert exec.getOutput().indexOf(expects) != -1 || exec.getError().indexOf(expects) != -1 : exec; - } finally { - if (ssh != null) - ssh.disconnect(); + SshClient ssh = computeContext.utils().sshFactory().create(socket, node.getCredentials().identity, + node.getCredentials().credential.getBytes()); + try { + ssh.connect(); + ExecResponse exec = ssh.exec(cmd); + assert exec.getOutput().indexOf(expects) != -1 || exec.getError().indexOf(expects) != -1 : exec; + } finally { + if (ssh != null) + ssh.disconnect(); + } } } diff --git a/compute/src/main/java/org/jclouds/compute/options/TemplateOptions.java b/compute/src/main/java/org/jclouds/compute/options/TemplateOptions.java index 93a22f6ee5..2f75bbb3d8 100644 --- a/compute/src/main/java/org/jclouds/compute/options/TemplateOptions.java +++ b/compute/src/main/java/org/jclouds/compute/options/TemplateOptions.java @@ -26,14 +26,19 @@ import static org.jclouds.io.Payloads.newStringPayload; import java.util.Arrays; +import javax.annotation.Nullable; + +import org.jclouds.compute.domain.OperatingSystem; +import org.jclouds.compute.predicates.OperatingSystemPredicates; import org.jclouds.io.Payload; +import org.jclouds.scriptbuilder.domain.OsFamily; +import org.jclouds.scriptbuilder.domain.Statement; /** - * Contains options supported in the {@code ComputeService#runNodesWithTag} - * operation.
* import static org.jclouds.compute.options.TemplateOptions.Builder.*;
@@ -207,8 +212,8 @@ public class TemplateOptions {
}
/**
- * This script will be executed as the root user upon system startup. This
- * script gets a prologue, so no #!/bin/bash required, path set up, etc
+ * This script will be executed as the root user upon system startup. This script gets a
+ * prologue, so no #!/bin/bash required, path set up, etc
*
* please use alternative that uses the {@link org.jclouds.io.Payload} object
*
@@ -220,19 +225,26 @@ public class TemplateOptions {
}
/**
- * This script will be executed as the root user upon system startup. This
- * script gets a prologue, so no #!/bin/bash required, path set up, etc
+ * This script will be executed as the root user upon system startup. This script gets a
+ * prologue, so no #!/bin/bash required, path set up, etc
*
* @see org.jclouds.io.Payloads
*/
public TemplateOptions runScript(Payload script) {
- checkArgument(
- checkNotNull(checkNotNull(script, "script").getContentLength(), "script.contentLength") <= 16 * 1024,
- "script cannot be larger than 16kb");
+ checkNotNull(script, "script");
this.script = script;
return this;
}
+ public TemplateOptions runScript(Statement script, @Nullable OperatingSystem os) {
+ return runScript(newStringPayload(checkNotNull(script, "script").render(
+ os == null || OperatingSystemPredicates.isUnix().apply(os) ? OsFamily.UNIX : OsFamily.WINDOWS)));
+ }
+
+ public TemplateOptions runScript(Statement script) {
+ return runScript(script, null);
+ }
+
/**
* replaces the rsa ssh key used at login.
*
@@ -243,7 +255,7 @@ public class TemplateOptions {
@Deprecated
public TemplateOptions installPrivateKey(String privateKey) {
checkArgument(checkNotNull(privateKey, "privateKey").startsWith("-----BEGIN RSA PRIVATE KEY-----"),
- "key should start with -----BEGIN RSA PRIVATE KEY-----");
+ "key should start with -----BEGIN RSA PRIVATE KEY-----");
Payload payload = newStringPayload(privateKey);
payload.setContentType("text/plain");
return installPrivateKey(payload);
@@ -265,8 +277,8 @@ public class TemplateOptions {
}
/**
- * if true, return when node(s) are NODE_RUNNING, if false, return as soon as
- * the server is provisioned.
+ * if true, return when node(s) are NODE_RUNNING, if false, return as soon as the server is
+ * provisioned.
*
* default is true
*/
@@ -344,8 +356,7 @@ public class TemplateOptions {
}
/**
- * please use alternative that uses the {@link org.jclouds.io.Payload}
- * object
+ * please use alternative that uses the {@link org.jclouds.io.Payload} object
*
* @see org.jclouds.io.Payloads
* @see #runScript(Payload)
@@ -366,8 +377,16 @@ public class TemplateOptions {
}
/**
- * please use alternative that uses the {@link org.jclouds.io.Payload}
- * object
+ * @see TemplateOptions#runScript
+ * @see org.jclouds.io.Payloads
+ */
+ public static TemplateOptions runScript(Statement script) {
+ TemplateOptions options = new TemplateOptions();
+ return options.runScript(script);
+ }
+
+ /**
+ * please use alternative that uses the {@link org.jclouds.io.Payload} object
*
* @see org.jclouds.io.Payloads
* @see #installPrivateKey(Payload)
@@ -388,8 +407,7 @@ public class TemplateOptions {
}
/**
- * please use alternative that uses the {@link org.jclouds.io.Payload}
- * object
+ * please use alternative that uses the {@link org.jclouds.io.Payload} object
*
* @see org.jclouds.io.Payloads
* @see #authorizePublicKey(Payload)
@@ -419,9 +437,9 @@ public class TemplateOptions {
@Override
public String toString() {
return "TemplateOptions [inboundPorts=" + Arrays.toString(inboundPorts) + ", privateKey=" + (privateKey != null)
- + ", publicKey=" + (publicKey != null) + ", runScript=" + (script != null) + ", blockUntilRunning="
- + blockUntilRunning + ", port:seconds=" + port + ":" + seconds + ", metadata/details: " + includeMetadata
- + "]";
+ + ", publicKey=" + (publicKey != null) + ", runScript=" + (script != null) + ", blockUntilRunning="
+ + blockUntilRunning + ", port:seconds=" + port + ":" + seconds + ", metadata/details: "
+ + includeMetadata + "]";
}
@Override
diff --git a/compute/src/main/java/org/jclouds/compute/predicates/OperatingSystemPredicates.java b/compute/src/main/java/org/jclouds/compute/predicates/OperatingSystemPredicates.java
index f7fd99fcbb..581c92b727 100644
--- a/compute/src/main/java/org/jclouds/compute/predicates/OperatingSystemPredicates.java
+++ b/compute/src/main/java/org/jclouds/compute/predicates/OperatingSystemPredicates.java
@@ -34,6 +34,33 @@ import com.google.common.collect.ImmutableSet;
* @author Adrian Cole
*/
public class OperatingSystemPredicates {
+ /**
+ * evaluates true if the OperatingSystem is unix like
+ *
+ */
+ public static Predicate isUnix() {
+ return new Predicate() {
+ @Override
+ public boolean apply(OperatingSystem os) {
+ if (os.getFamily() != null) {
+ switch (os.getFamily()) {
+ case WINDOWS:
+ return false;
+ }
+ }
+ for (String toMatch : ImmutableSet.of(os.getName(), os.getDescription()))
+ if (toMatch != null && toMatch.toLowerCase().indexOf("windows") != -1)
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "isUnix()";
+ }
+ };
+ }
+
/**
* evaluates true if the OperatingSystem supports the apt installer
*
diff --git a/compute/src/main/java/org/jclouds/compute/util/ComputeServiceUtils.java b/compute/src/main/java/org/jclouds/compute/util/ComputeServiceUtils.java
index c175579da3..6a79d2c7bd 100644
--- a/compute/src/main/java/org/jclouds/compute/util/ComputeServiceUtils.java
+++ b/compute/src/main/java/org/jclouds/compute/util/ComputeServiceUtils.java
@@ -19,6 +19,12 @@
package org.jclouds.compute.util;
+import static com.google.common.base.Throwables.getStackTraceAsString;
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.find;
+import static org.jclouds.scriptbuilder.domain.Statements.pipeHttpResponseToBash;
+
+import java.net.URI;
import java.util.Formatter;
import java.util.Map;
import java.util.NoSuchElementException;
@@ -38,15 +44,13 @@ import org.jclouds.compute.domain.internal.NodeMetadataImpl;
import org.jclouds.domain.Credentials;
import org.jclouds.http.HttpRequest;
import org.jclouds.logging.Logger;
+import org.jclouds.scriptbuilder.domain.Statement;
+import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.ssh.SshClient;
import org.jclouds.util.Utils;
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
-import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
/**
*
@@ -60,17 +64,25 @@ public class ComputeServiceUtils {
*
* @return a shell script that will invoke the http request
*/
- public static String buildCurlsh(HttpRequest request) {
- String headers = Joiner.on(' ').join(
- Iterables.transform(request.getHeaders().entries(), new Function, String>() {
+ public static Statement execHttpResponse(HttpRequest request) {
+ return pipeHttpResponseToBash(request.getMethod(), request.getEndpoint(), request.getHeaders());
+ }
- @Override
- public String apply(Entry from) {
- return String.format("-H \"%s: %s\"", from.getKey(), from.getValue());
- }
+ public static Statement execHttpResponse(URI location) {
+ return execHttpResponse(new HttpRequest("GET", location));
+ }
- }));
- return String.format("curl -s --retry 20 %s %s |bash\n", headers, request.getEndpoint().toASCIIString());
+ /**
+ * build a shell script that invokes the contents of the http request in bash.
+ *
+ * @return a shell script that will invoke the http request
+ */
+ public static Statement extractTargzIntoDirectory(HttpRequest targz, String directory) {
+ return Statements.extractTargzIntoDirectory(targz.getMethod(), targz.getEndpoint(), targz.getHeaders(), directory);
+ }
+
+ public static Statement extractTargzIntoDirectory(URI targz, String directory) {
+ return extractTargzIntoDirectory(new HttpRequest("GET", targz), directory);
}
public static String parseTagFromName(String from) {
@@ -113,11 +125,11 @@ public class ComputeServiceUtils {
if (NAME_VERSION_MAP.containsKey(family)) {
CONTAINS_SUBSTRING contains = new CONTAINS_SUBSTRING(in.replace('-', '.'));
try {
- String key = Iterables.find(NAME_VERSION_MAP.get(family).keySet(), contains);
+ String key = find(NAME_VERSION_MAP.get(family).keySet(), contains);
return NAME_VERSION_MAP.get(family).get(key);
} catch (NoSuchElementException e) {
try {
- return Iterables.find(NAME_VERSION_MAP.get(family).values(), contains);
+ return find(NAME_VERSION_MAP.get(family).values(), contains);
} catch (NoSuchElementException e1) {
}
}
@@ -140,7 +152,7 @@ public class ComputeServiceUtils {
int index = 1;
for (Entry, Exception> errorMessage : executionExceptions.entrySet()) {
fmt.format("%s) %s on %s:%n%s%n%n", index++, errorMessage.getValue().getClass().getSimpleName(), errorMessage
- .getKey(), Throwables.getStackTraceAsString(errorMessage.getValue()));
+ .getKey(), getStackTraceAsString(errorMessage.getValue()));
}
return fmt.format("%s error[s]", executionExceptions.size()).toString();
}
@@ -150,14 +162,14 @@ public class ComputeServiceUtils {
int index = 1;
for (Entry extends NodeMetadata, ? extends Throwable> errorMessage : failedNodes.entrySet()) {
fmt.format("%s) %s on node %s:%n%s%n%n", index++, errorMessage.getValue().getClass().getSimpleName(),
- errorMessage.getKey().getId(), Throwables.getStackTraceAsString(errorMessage.getValue()));
+ errorMessage.getKey().getId(), getStackTraceAsString(errorMessage.getValue()));
}
return fmt.format("%s error[s]", failedNodes.size()).toString();
}
public static Iterable extends ComputeMetadata> filterByName(Iterable extends ComputeMetadata> nodes,
final String name) {
- return Iterables.filter(nodes, new Predicate() {
+ return filter(nodes, new Predicate() {
@Override
public boolean apply(ComputeMetadata input) {
return input.getName().equalsIgnoreCase(name);
diff --git a/compute/src/test/java/org/jclouds/compute/util/ComputeServiceUtilsTest.java b/compute/src/test/java/org/jclouds/compute/util/ComputeServiceUtilsTest.java
index 7322ac597f..e7e9d5489c 100644
--- a/compute/src/test/java/org/jclouds/compute/util/ComputeServiceUtilsTest.java
+++ b/compute/src/test/java/org/jclouds/compute/util/ComputeServiceUtilsTest.java
@@ -24,6 +24,7 @@ import static org.testng.Assert.assertEquals;
import java.net.URI;
import org.jclouds.http.HttpRequest;
+import org.jclouds.scriptbuilder.domain.OsFamily;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
@@ -38,14 +39,26 @@ import com.google.common.collect.ImmutableMultimap;
public class ComputeServiceUtilsTest {
@Test
- public void testCurlSh() {
+ public void testExecHttpResponse() {
HttpRequest request = new HttpRequest("GET", URI.create("https://adriancolehappy.s3.amazonaws.com/java/install"),
ImmutableMultimap.of("Host", "adriancolehappy.s3.amazonaws.com", "Date",
"Sun, 12 Sep 2010 08:25:19 GMT", "Authorization", "AWS 0ASHDJAS82:JASHFDA="));
assertEquals(
- ComputeServiceUtils.buildCurlsh(request),
- "curl -s --retry 20 -H \"Host: adriancolehappy.s3.amazonaws.com\" -H \"Date: Sun, 12 Sep 2010 08:25:19 GMT\" -H \"Authorization: AWS 0ASHDJAS82:JASHFDA=\" https://adriancolehappy.s3.amazonaws.com/java/install |bash\n");
+ ComputeServiceUtils.execHttpResponse(request).render(OsFamily.UNIX),
+ "curl -X GET -s --retry 20 -H \"Host: adriancolehappy.s3.amazonaws.com\" -H \"Date: Sun, 12 Sep 2010 08:25:19 GMT\" -H \"Authorization: AWS 0ASHDJAS82:JASHFDA=\" https://adriancolehappy.s3.amazonaws.com/java/install |(bash)\n");
+
+ }
+
+ @Test
+ public void testTarxzpHttpResponse() {
+ HttpRequest request = new HttpRequest("GET", URI.create("https://adriancolehappy.s3.amazonaws.com/java/install"),
+ ImmutableMultimap.of("Host", "adriancolehappy.s3.amazonaws.com", "Date",
+ "Sun, 12 Sep 2010 08:25:19 GMT", "Authorization", "AWS 0ASHDJAS82:JASHFDA="));
+
+ assertEquals(
+ ComputeServiceUtils.extractTargzIntoDirectory(request, "/stage/").render(OsFamily.UNIX),
+ "curl -X GET -s --retry 20 -H \"Host: adriancolehappy.s3.amazonaws.com\" -H \"Date: Sun, 12 Sep 2010 08:25:19 GMT\" -H \"Authorization: AWS 0ASHDJAS82:JASHFDA=\" https://adriancolehappy.s3.amazonaws.com/java/install |(mkdir -p /stage/ &&cd /stage/ &&tar -xpzf -)\n");
}
}
diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/PipeHttpResponseTo.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/PipeHttpResponseTo.java
new file mode 100644
index 0000000000..2c63d23abc
--- /dev/null
+++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/PipeHttpResponseTo.java
@@ -0,0 +1,65 @@
+/**
+ *
+ * Copyright (C) 2010 Cloud Conscious, LLC.
+ *
+ * ====================================================================
+ * 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.jclouds.scriptbuilder.domain;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.net.URI;
+import java.util.Map.Entry;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimap;
+
+/**
+ * Pipes the content of the http response to a shell command that accepts input from stdin
+ *
+ * @author Adrian Cole
+ */
+public class PipeHttpResponseTo extends InterpretableStatement {
+ /**
+ *
+ * @param toExec
+ * what to invoke
+ * @param method
+ * http method: ex GET
+ * @param endpoint
+ * uri corresponding to the request
+ * @param headers
+ * request headers to send
+ */
+ public PipeHttpResponseTo(Statement toExec, String method, URI endpoint, Multimap headers) {
+ super(String.format("curl -X %s -s --retry 20 %s %s |(%s)\n", method, Joiner.on(' ').join(
+ Iterables.transform(headers.entries(), new Function, String>() {
+
+ @Override
+ public String apply(Entry from) {
+ return String.format("-H \"%s: %s\"", from.getKey(), from.getValue());
+ }
+
+ })), endpoint.toASCIIString(), toExec.render(OsFamily.UNIX)));
+ }
+
+ public String render(OsFamily family) {
+ checkArgument(family != OsFamily.WINDOWS, "windows not supported");
+ return super.render(family);
+ }
+}
\ No newline at end of file
diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/PipeHttpResponseToBash.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/PipeHttpResponseToBash.java
new file mode 100644
index 0000000000..2e7d4ce462
--- /dev/null
+++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/PipeHttpResponseToBash.java
@@ -0,0 +1,46 @@
+/**
+ *
+ * Copyright (C) 2010 Cloud Conscious, LLC.
+ *
+ * ====================================================================
+ * 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.jclouds.scriptbuilder.domain;
+
+import java.net.URI;
+
+import com.google.common.collect.Multimap;
+
+/**
+ * Pipes the content of the http response to bash
+ *
+ * @author Adrian Cole
+ */
+public class PipeHttpResponseToBash extends PipeHttpResponseTo {
+ /**
+ *
+ *
+ * @param method
+ * http method: ex GET
+ * @param endpoint
+ * uri corresponding to the request
+ * @param headers
+ * request headers to send
+ */
+ public PipeHttpResponseToBash(String method, URI endpoint, Multimap headers) {
+ super(Statements.interpret("bash"), method, endpoint, headers);
+ }
+
+}
\ No newline at end of file
diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/PipeHttpResponseToTarxpzfIntoDirectory.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/PipeHttpResponseToTarxpzfIntoDirectory.java
new file mode 100644
index 0000000000..2fb6c65e51
--- /dev/null
+++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/PipeHttpResponseToTarxpzfIntoDirectory.java
@@ -0,0 +1,47 @@
+/**
+ *
+ * Copyright (C) 2010 Cloud Conscious, LLC.
+ *
+ * ====================================================================
+ * 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.jclouds.scriptbuilder.domain;
+
+import java.net.URI;
+
+import com.google.common.collect.Multimap;
+
+/**
+ * Pipes the content of the http response to tar -xpzf
+ *
+ * @author Adrian Cole
+ */
+public class PipeHttpResponseToTarxpzfIntoDirectory extends PipeHttpResponseTo {
+ /**
+ *
+ *
+ * @param method
+ * http method: ex GET
+ * @param endpoint
+ * uri corresponding to the request
+ * @param headers
+ * request headers to send
+ */
+ public PipeHttpResponseToTarxpzfIntoDirectory(String method, URI endpoint, Multimap headers,
+ String directory) {
+ super(Statements.interpret(String.format("{md} %s &&{cd} %s &&tar -xpzf -", directory, directory)), method,
+ endpoint, headers);
+ }
+}
\ No newline at end of file
diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/Statements.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/Statements.java
index fdb69039c5..ebf7207d73 100644
--- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/Statements.java
+++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/domain/Statements.java
@@ -19,8 +19,11 @@
package org.jclouds.scriptbuilder.domain;
+import java.net.URI;
import java.util.Map;
+import com.google.common.collect.Multimap;
+
/**
* Statements used in shell scripts.
*
@@ -97,7 +100,7 @@ public class Statements {
*
* @see ShellToken
*/
- public static Statement interpret(String ... portableStatements) {
+ public static Statement interpret(String... portableStatements) {
return new InterpretableStatement(portableStatements);
}
@@ -107,4 +110,33 @@ public class Statements {
public static Statement exec(String portableStatement) {
return interpret(portableStatement + "{lf}");
}
+
+ /**
+ * untar, ungzip the data received from the request parameters.
+ *
+ * @param method
+ * http method: ex GET
+ * @param endpoint
+ * uri corresponding to the request
+ * @param headers
+ * request headers to send
+ */
+ public static Statement extractTargzIntoDirectory(String method, URI endpoint, Multimap headers,
+ String directory) {
+ return new PipeHttpResponseToTarxpzfIntoDirectory( method, endpoint, headers,directory);
+ }
+
+ /**
+ * exec the data received from the request parameters.
+ *
+ * @param method
+ * http method: ex GET
+ * @param endpoint
+ * uri corresponding to the request
+ * @param headers
+ * request headers to send
+ */
+ public static Statement pipeHttpResponseToBash(String method, URI endpoint, Multimap headers) {
+ return new PipeHttpResponseToBash(method, endpoint, headers);
+ }
}
\ No newline at end of file
diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/PipeHttpResponseToTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/PipeHttpResponseToTest.java
new file mode 100644
index 0000000000..5c8fa31e49
--- /dev/null
+++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/PipeHttpResponseToTest.java
@@ -0,0 +1,76 @@
+/**
+ *
+ * Copyright (C) 2010 Cloud Conscious, LLC.
+ *
+ * ====================================================================
+ * 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.jclouds.scriptbuilder.domain;
+
+import static org.testng.Assert.assertEquals;
+
+import java.net.URI;
+
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMultimap;
+
+/**
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "scriptbuilder.PipeHttpResponseToTest")
+public class PipeHttpResponseToTest {
+ PipeHttpResponseTo bash = new PipeHttpResponseTo(Statements.interpret("bash"), "GET", URI
+ .create("https://adriancolehappy.s3.amazonaws.com/java/install"), ImmutableMultimap.of("Host",
+ "adriancolehappy.s3.amazonaws.com", "Date", "Sun, 12 Sep 2010 08:25:19 GMT", "Authorization",
+ "AWS 0ASHDJAS82:JASHFDA="));
+
+ PipeHttpResponseToBash bash2 = new PipeHttpResponseToBash("GET", URI
+ .create("https://adriancolehappy.s3.amazonaws.com/java/install"), ImmutableMultimap.of("Host",
+ "adriancolehappy.s3.amazonaws.com", "Date", "Sun, 12 Sep 2010 08:25:19 GMT", "Authorization",
+ "AWS 0ASHDJAS82:JASHFDA="));
+
+ public void testPipeHttpResponseToBashUNIX() {
+ assertEquals(
+ bash.render(OsFamily.UNIX),
+ "curl -X GET -s --retry 20 -H \"Host: adriancolehappy.s3.amazonaws.com\" -H \"Date: Sun, 12 Sep 2010 08:25:19 GMT\" -H \"Authorization: AWS 0ASHDJAS82:JASHFDA=\" https://adriancolehappy.s3.amazonaws.com/java/install |(bash)\n");
+ assertEquals(bash2.render(OsFamily.UNIX), bash.render(OsFamily.UNIX));
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void testPipeHttpResponseToBashWINDOWS() {
+ bash.render(OsFamily.WINDOWS);
+ }
+
+ PipeHttpResponseTo untar = new PipeHttpResponseTo(Statements
+ .interpret("{md} {root}stage{fs} &&{cd} {root}stage{fs} &&tar -xpzf -"), "GET", URI
+ .create("https://adriancolehappy.s3.amazonaws.com/java/install"), ImmutableMultimap.of("Host",
+ "adriancolehappy.s3.amazonaws.com", "Date", "Sun, 12 Sep 2010 08:25:19 GMT", "Authorization",
+ "AWS 0ASHDJAS82:JASHFDA="));
+
+ PipeHttpResponseTo untar2 = new PipeHttpResponseToTarxpzfIntoDirectory( "GET", URI
+ .create("https://adriancolehappy.s3.amazonaws.com/java/install"), ImmutableMultimap.of("Host",
+ "adriancolehappy.s3.amazonaws.com", "Date", "Sun, 12 Sep 2010 08:25:19 GMT", "Authorization",
+ "AWS 0ASHDJAS82:JASHFDA="),"{root}stage{fs}");
+
+ public void testPipeHttpResponseToUntarUNIX() {
+ assertEquals(
+ untar.render(OsFamily.UNIX),
+ "curl -X GET -s --retry 20 -H \"Host: adriancolehappy.s3.amazonaws.com\" -H \"Date: Sun, 12 Sep 2010 08:25:19 GMT\" -H \"Authorization: AWS 0ASHDJAS82:JASHFDA=\" https://adriancolehappy.s3.amazonaws.com/java/install |(mkdir -p /stage/ &&cd /stage/ &&tar -xpzf -)\n");
+ assertEquals(untar.render(OsFamily.UNIX), untar2.render(OsFamily.UNIX));
+
+ }
+
+}