added statements for extracting targzs and running commands from a http request

This commit is contained in:
Adrian Cole 2010-09-12 17:35:51 -07:00
parent 0e15e52a70
commit 00361f859b
11 changed files with 424 additions and 70 deletions

View File

@ -21,18 +21,23 @@ package org.jclouds.aws;
import static org.jclouds.compute.BaseComputeServiceLiveTest.buildScript; import static org.jclouds.compute.BaseComputeServiceLiveTest.buildScript;
import static org.jclouds.compute.options.TemplateOptions.Builder.runScript; import static org.jclouds.compute.options.TemplateOptions.Builder.runScript;
import static org.jclouds.compute.util.ComputeServiceUtils.buildCurlsh; import static org.jclouds.compute.util.ComputeServiceUtils.execHttpResponse;
import static org.jclouds.io.Payloads.newStringPayload; 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.aws.ec2.compute.BlobStoreAndComputeServiceLiveTest;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.compute.RunNodesException; import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.OperatingSystem; import org.jclouds.compute.domain.OperatingSystem;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.scriptbuilder.domain.Statement;
import org.testng.annotations.Test; import org.testng.annotations.Test;
/** /**
* This test helps us understand how we can use the power of blobstores to our favor.
* *
* @author Adrian Cole * @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 * 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 * 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 * that can be fully specified without headers (ex. Amazon S3). Instead, we use a variant
* (curlsh). * (execHttpResponse).
* <p/> * <p/>
* 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
* <p/> * <p/>
* With this script ready, any node or nodes will take instructions from the blobstore when it * With this script ready, any node or nodes will take instructions from the blobstore when it
* boots up. we verify this with an assertion. * 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. // configured for amz. Note we are getting temporary access to a private blob.
HttpRequest signedRequestOfInstallScript = blobContext.getBlobStore().signRequestForBlob(tag, "openjdk/install"); HttpRequest signedRequestOfInstallScript = blobContext.getBlobStore().signRequestForBlob(tag, "openjdk/install");
// instruct the bootstrap to pull the script from the blobstore and invoke it directly with bash. // so one of our commands is to execute the contents of the blob above
TemplateOptions runOpenJDKInstallDirectlyFromBlobStore = runScript(newStringPayload(buildCurlsh(signedRequestOfInstallScript))); 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 // now that we have the correct instructions, kick-off the provisioner
Iterable<? extends NodeMetadata> nodes = computeContext.getComputeService().runNodesWithTag(tag, 1, Iterable<? extends NodeMetadata> nodes = computeContext.getComputeService().runNodesWithTag(tag, 2,
runOpenJDKInstallDirectlyFromBlobStore); runScript(bootstrapInstructions));
// ensure the bootstrap operated by checking for a known signature of success. // ensure the bootstrap operated by checking for the components we installed at boot time.
assertSshOutputOfCommandContains(nodes, "openjdk -version", "OpenJDK"); // 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 + "");
} }
} }

View File

@ -64,20 +64,20 @@ public class BlobStoreAndComputeServiceLiveTest {
setupCredentials(); setupCredentials();
computeContext = new ComputeServiceContextFactory().createContext(computeServiceProvider, identity, credential, computeContext = new ComputeServiceContextFactory().createContext(computeServiceProvider, identity, credential,
ImmutableSet.of(new Log4JLoggingModule(), new JschSshClientModule())); ImmutableSet.of(new Log4JLoggingModule(), new JschSshClientModule()));
blobContext = new BlobStoreContextFactory().createContext(blobStoreProvider, identity, credential, blobContext = new BlobStoreContextFactory().createContext(blobStoreProvider, identity, credential, ImmutableSet
ImmutableSet.of(new Log4JLoggingModule())); .of(new Log4JLoggingModule()));
blobContext.getAsyncBlobStore().createContainerInLocation(null, tag); blobContext.getAsyncBlobStore().createContainerInLocation(null, tag);
computeContext.getComputeService().destroyNodesMatching(NodePredicates.withTag(tag)); computeContext.getComputeService().destroyNodesMatching(NodePredicates.withTag(tag));
} }
protected void assertSshOutputOfCommandContains(Iterable<? extends NodeMetadata> nodes, String cmd, String expects) { 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, SshClient ssh = computeContext.utils().sshFactory().create(socket, node.getCredentials().identity,
get(nodes, 0).getCredentials().credential.getBytes()); node.getCredentials().credential.getBytes());
try { try {
ssh.connect(); ssh.connect();
;
ExecResponse exec = ssh.exec(cmd); ExecResponse exec = ssh.exec(cmd);
assert exec.getOutput().indexOf(expects) != -1 || exec.getError().indexOf(expects) != -1 : exec; assert exec.getOutput().indexOf(expects) != -1 || exec.getError().indexOf(expects) != -1 : exec;
} finally { } finally {
@ -85,6 +85,7 @@ public class BlobStoreAndComputeServiceLiveTest {
ssh.disconnect(); ssh.disconnect();
} }
} }
}
protected void uploadBlob(String container, String name, String script) { protected void uploadBlob(String container, String name, String script) {
Blob blob = blobContext.getBlobStore().newBlob(name); Blob blob = blobContext.getBlobStore().newBlob(name);

View File

@ -26,14 +26,19 @@ import static org.jclouds.io.Payloads.newStringPayload;
import java.util.Arrays; 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.io.Payload;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.Statement;
/** /**
* Contains options supported in the {@code ComputeService#runNodesWithTag} * Contains options supported in the {@code ComputeService#runNodesWithTag} operation. <h2>
* operation. <h2> * Usage</h2> The recommended way to instantiate a TemplateOptions object is to statically import
* Usage</h2> The recommended way to instantiate a TemplateOptions object is to * TemplateOptions.* and invoke a static creation method followed by an instance mutator (if
* statically import TemplateOptions.* and invoke a static creation method * needed):
* followed by an instance mutator (if needed):
* <p/> * <p/>
* <code> * <code>
* import static org.jclouds.compute.options.TemplateOptions.Builder.*; * 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 * This script will be executed as the root user upon system startup. This script gets a
* script gets a prologue, so no #!/bin/bash required, path set up, etc * prologue, so no #!/bin/bash required, path set up, etc
* <p/> * <p/>
* please use alternative that uses the {@link org.jclouds.io.Payload} object * 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 * This script will be executed as the root user upon system startup. This script gets a
* script gets a prologue, so no #!/bin/bash required, path set up, etc * prologue, so no #!/bin/bash required, path set up, etc
* *
* @see org.jclouds.io.Payloads * @see org.jclouds.io.Payloads
*/ */
public TemplateOptions runScript(Payload script) { public TemplateOptions runScript(Payload script) {
checkArgument( checkNotNull(script, "script");
checkNotNull(checkNotNull(script, "script").getContentLength(), "script.contentLength") <= 16 * 1024,
"script cannot be larger than 16kb");
this.script = script; this.script = script;
return this; 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. * replaces the rsa ssh key used at login.
* <p/> * <p/>
@ -265,8 +277,8 @@ public class TemplateOptions {
} }
/** /**
* if true, return when node(s) are NODE_RUNNING, if false, return as soon as * if true, return when node(s) are NODE_RUNNING, if false, return as soon as the server is
* the server is provisioned. * provisioned.
* <p/> * <p/>
* default is true * default is true
*/ */
@ -344,8 +356,7 @@ public class TemplateOptions {
} }
/** /**
* please use alternative that uses the {@link org.jclouds.io.Payload} * please use alternative that uses the {@link org.jclouds.io.Payload} object
* object
* *
* @see org.jclouds.io.Payloads * @see org.jclouds.io.Payloads
* @see #runScript(Payload) * @see #runScript(Payload)
@ -366,8 +377,16 @@ public class TemplateOptions {
} }
/** /**
* please use alternative that uses the {@link org.jclouds.io.Payload} * @see TemplateOptions#runScript
* object * @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 org.jclouds.io.Payloads
* @see #installPrivateKey(Payload) * @see #installPrivateKey(Payload)
@ -388,8 +407,7 @@ public class TemplateOptions {
} }
/** /**
* please use alternative that uses the {@link org.jclouds.io.Payload} * please use alternative that uses the {@link org.jclouds.io.Payload} object
* object
* *
* @see org.jclouds.io.Payloads * @see org.jclouds.io.Payloads
* @see #authorizePublicKey(Payload) * @see #authorizePublicKey(Payload)
@ -420,8 +438,8 @@ public class TemplateOptions {
public String toString() { public String toString() {
return "TemplateOptions [inboundPorts=" + Arrays.toString(inboundPorts) + ", privateKey=" + (privateKey != null) return "TemplateOptions [inboundPorts=" + Arrays.toString(inboundPorts) + ", privateKey=" + (privateKey != null)
+ ", publicKey=" + (publicKey != null) + ", runScript=" + (script != null) + ", blockUntilRunning=" + ", publicKey=" + (publicKey != null) + ", runScript=" + (script != null) + ", blockUntilRunning="
+ blockUntilRunning + ", port:seconds=" + port + ":" + seconds + ", metadata/details: " + includeMetadata + blockUntilRunning + ", port:seconds=" + port + ":" + seconds + ", metadata/details: "
+ "]"; + includeMetadata + "]";
} }
@Override @Override

View File

@ -34,6 +34,33 @@ import com.google.common.collect.ImmutableSet;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class OperatingSystemPredicates { public class OperatingSystemPredicates {
/**
* evaluates true if the OperatingSystem is unix like
*
*/
public static Predicate<OperatingSystem> isUnix() {
return new Predicate<OperatingSystem>() {
@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 * evaluates true if the OperatingSystem supports the apt installer
* *

View File

@ -19,6 +19,12 @@
package org.jclouds.compute.util; 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.Formatter;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
@ -38,15 +44,13 @@ import org.jclouds.compute.domain.internal.NodeMetadataImpl;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.logging.Logger; 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.ssh.SshClient;
import org.jclouds.util.Utils; 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.Predicate;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap; 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 * @return a shell script that will invoke the http request
*/ */
public static String buildCurlsh(HttpRequest request) { public static Statement execHttpResponse(HttpRequest request) {
String headers = Joiner.on(' ').join( return pipeHttpResponseToBash(request.getMethod(), request.getEndpoint(), request.getHeaders());
Iterables.transform(request.getHeaders().entries(), new Function<Entry<String, String>, String>() {
@Override
public String apply(Entry<String, String> from) {
return String.format("-H \"%s: %s\"", from.getKey(), from.getValue());
} }
})); public static Statement execHttpResponse(URI location) {
return String.format("curl -s --retry 20 %s %s |bash\n", headers, request.getEndpoint().toASCIIString()); return execHttpResponse(new HttpRequest("GET", location));
}
/**
* 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) { public static String parseTagFromName(String from) {
@ -113,11 +125,11 @@ public class ComputeServiceUtils {
if (NAME_VERSION_MAP.containsKey(family)) { if (NAME_VERSION_MAP.containsKey(family)) {
CONTAINS_SUBSTRING contains = new CONTAINS_SUBSTRING(in.replace('-', '.')); CONTAINS_SUBSTRING contains = new CONTAINS_SUBSTRING(in.replace('-', '.'));
try { 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); return NAME_VERSION_MAP.get(family).get(key);
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
try { try {
return Iterables.find(NAME_VERSION_MAP.get(family).values(), contains); return find(NAME_VERSION_MAP.get(family).values(), contains);
} catch (NoSuchElementException e1) { } catch (NoSuchElementException e1) {
} }
} }
@ -140,7 +152,7 @@ public class ComputeServiceUtils {
int index = 1; int index = 1;
for (Entry<?, Exception> errorMessage : executionExceptions.entrySet()) { for (Entry<?, Exception> errorMessage : executionExceptions.entrySet()) {
fmt.format("%s) %s on %s:%n%s%n%n", index++, errorMessage.getValue().getClass().getSimpleName(), errorMessage 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(); return fmt.format("%s error[s]", executionExceptions.size()).toString();
} }
@ -150,14 +162,14 @@ public class ComputeServiceUtils {
int index = 1; int index = 1;
for (Entry<? extends NodeMetadata, ? extends Throwable> errorMessage : failedNodes.entrySet()) { 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(), 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(); return fmt.format("%s error[s]", failedNodes.size()).toString();
} }
public static Iterable<? extends ComputeMetadata> filterByName(Iterable<? extends ComputeMetadata> nodes, public static Iterable<? extends ComputeMetadata> filterByName(Iterable<? extends ComputeMetadata> nodes,
final String name) { final String name) {
return Iterables.filter(nodes, new Predicate<ComputeMetadata>() { return filter(nodes, new Predicate<ComputeMetadata>() {
@Override @Override
public boolean apply(ComputeMetadata input) { public boolean apply(ComputeMetadata input) {
return input.getName().equalsIgnoreCase(name); return input.getName().equalsIgnoreCase(name);

View File

@ -24,6 +24,7 @@ import static org.testng.Assert.assertEquals;
import java.net.URI; import java.net.URI;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap;
@ -38,14 +39,26 @@ import com.google.common.collect.ImmutableMultimap;
public class ComputeServiceUtilsTest { public class ComputeServiceUtilsTest {
@Test @Test
public void testCurlSh() { public void testExecHttpResponse() {
HttpRequest request = new HttpRequest("GET", URI.create("https://adriancolehappy.s3.amazonaws.com/java/install"), HttpRequest request = new HttpRequest("GET", URI.create("https://adriancolehappy.s3.amazonaws.com/java/install"),
ImmutableMultimap.of("Host", "adriancolehappy.s3.amazonaws.com", "Date", ImmutableMultimap.of("Host", "adriancolehappy.s3.amazonaws.com", "Date",
"Sun, 12 Sep 2010 08:25:19 GMT", "Authorization", "AWS 0ASHDJAS82:JASHFDA=")); "Sun, 12 Sep 2010 08:25:19 GMT", "Authorization", "AWS 0ASHDJAS82:JASHFDA="));
assertEquals( assertEquals(
ComputeServiceUtils.buildCurlsh(request), ComputeServiceUtils.execHttpResponse(request).render(OsFamily.UNIX),
"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"); "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");
} }
} }

View File

@ -0,0 +1,65 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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<String, String> headers) {
super(String.format("curl -X %s -s --retry 20 %s %s |(%s)\n", method, Joiner.on(' ').join(
Iterables.transform(headers.entries(), new Function<Entry<String, String>, String>() {
@Override
public String apply(Entry<String, String> 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);
}
}

View File

@ -0,0 +1,46 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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<String, String> headers) {
super(Statements.interpret("bash"), method, endpoint, headers);
}
}

View File

@ -0,0 +1,47 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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<String, String> headers,
String directory) {
super(Statements.interpret(String.format("{md} %s &&{cd} %s &&tar -xpzf -", directory, directory)), method,
endpoint, headers);
}
}

View File

@ -19,8 +19,11 @@
package org.jclouds.scriptbuilder.domain; package org.jclouds.scriptbuilder.domain;
import java.net.URI;
import java.util.Map; import java.util.Map;
import com.google.common.collect.Multimap;
/** /**
* Statements used in shell scripts. * Statements used in shell scripts.
* *
@ -107,4 +110,33 @@ public class Statements {
public static Statement exec(String portableStatement) { public static Statement exec(String portableStatement) {
return interpret(portableStatement + "{lf}"); 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<String, String> 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<String, String> headers) {
return new PipeHttpResponseToBash(method, endpoint, headers);
}
} }

View File

@ -0,0 +1,76 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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));
}
}