mirror of https://github.com/apache/jclouds.git
added statements for extracting targzs and running commands from a http request
This commit is contained in:
parent
0e15e52a70
commit
00361f859b
|
@ -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).
|
||||
* <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/>
|
||||
* 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 + "");
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,20 +64,20 @@ 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());
|
||||
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 {
|
||||
|
@ -85,6 +85,7 @@ public class BlobStoreAndComputeServiceLiveTest {
|
|||
ssh.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void uploadBlob(String container, String name, String script) {
|
||||
Blob blob = blobContext.getBlobStore().newBlob(name);
|
||||
|
|
|
@ -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. <h2>
|
||||
* Usage</h2> The recommended way to instantiate a TemplateOptions object is to
|
||||
* statically import TemplateOptions.* and invoke a static creation method
|
||||
* followed by an instance mutator (if needed):
|
||||
* Contains options supported in the {@code ComputeService#runNodesWithTag} operation. <h2>
|
||||
* Usage</h2> The recommended way to instantiate a TemplateOptions object is to statically import
|
||||
* TemplateOptions.* and invoke a static creation method followed by an instance mutator (if
|
||||
* needed):
|
||||
* <p/>
|
||||
* <code>
|
||||
* 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
|
||||
* <p/>
|
||||
* 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.
|
||||
* <p/>
|
||||
|
@ -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.
|
||||
* <p/>
|
||||
* 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)
|
||||
|
@ -420,8 +438,8 @@ public class TemplateOptions {
|
|||
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
|
||||
+ "]";
|
||||
+ blockUntilRunning + ", port:seconds=" + port + ":" + seconds + ", metadata/details: "
|
||||
+ includeMetadata + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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<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
|
||||
*
|
||||
|
|
|
@ -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<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(HttpRequest request) {
|
||||
return pipeHttpResponseToBash(request.getMethod(), request.getEndpoint(), request.getHeaders());
|
||||
}
|
||||
|
||||
}));
|
||||
return String.format("curl -s --retry 20 %s %s |bash\n", headers, request.getEndpoint().toASCIIString());
|
||||
public static Statement execHttpResponse(URI location) {
|
||||
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) {
|
||||
|
@ -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<ComputeMetadata>() {
|
||||
return filter(nodes, new Predicate<ComputeMetadata>() {
|
||||
@Override
|
||||
public boolean apply(ComputeMetadata input) {
|
||||
return input.getName().equalsIgnoreCase(name);
|
||||
|
|
|
@ -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");
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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<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);
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue