Issue 357:Init script should check for errors + herefile fixes + script events

This commit is contained in:
Adrian Cole 2012-02-19 01:51:35 +02:00
parent ccc86123ca
commit 636c3bb6e5
82 changed files with 2409 additions and 1494 deletions

View File

@ -47,7 +47,7 @@ import org.apache.tools.ant.types.Environment;
import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.Environment.Variable; import org.apache.tools.ant.types.Environment.Variable;
import org.jclouds.scriptbuilder.InitBuilder; import org.jclouds.scriptbuilder.InitScript;
import org.jclouds.scriptbuilder.domain.OsFamily; import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.ShellToken; import org.jclouds.scriptbuilder.domain.ShellToken;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
@ -237,13 +237,13 @@ public class SSHJava extends Java {
private int sshexecRedirectStreams(Statement statement) throws IOException { private int sshexecRedirectStreams(Statement statement) throws IOException {
exec.setStreamHandler(redirector.createHandler()); exec.setStreamHandler(redirector.createHandler());
log("starting java as:\n" + statement.render(osFamily), Project.MSG_VERBOSE); log("starting java as:\n" + statement.render(osFamily), Project.MSG_VERBOSE);
int rc; int exitStatus;
try { try {
rc = sshexec(statement.render(osFamily)); exitStatus = sshexec(statement.render(osFamily));
} finally { } finally {
redirector.complete(); redirector.complete();
} }
return rc; return exitStatus;
} }
private void mkdirAndCopyTo(String destination, Iterable<FileSet> sets) { private void mkdirAndCopyTo(String destination, Iterable<FileSet> sets) {
@ -373,8 +373,8 @@ public class SSHJava extends Java {
Joiner.on(' ').join(commandLine.getJavaCommand().getArguments())); Joiner.on(' ').join(commandLine.getJavaCommand().getArguments()));
} }
InitBuilder testInitBuilder = new InitBuilder(id, basedir, basedir, envVariables, InitScript testInitBuilder = InitScript.builder().name(id).home(basedir).exportVariables(envVariables)
ImmutableList.<Statement> of(Statements.interpret( commandBuilder.toString()))); .run(Statements.interpret( commandBuilder.toString())).build();
return testInitBuilder.render(osFamily); return testInitBuilder.render(osFamily);
} }

View File

@ -40,6 +40,8 @@ import org.jclouds.domain.LoginCredentials;
import org.jclouds.ec2.domain.Attachment; import org.jclouds.ec2.domain.Attachment;
import org.jclouds.ec2.domain.BlockDevice; import org.jclouds.ec2.domain.BlockDevice;
import org.jclouds.ec2.domain.Image; import org.jclouds.ec2.domain.Image;
import org.jclouds.ec2.domain.Image.Architecture;
import org.jclouds.ec2.domain.Image.ImageType;
import org.jclouds.ec2.domain.InstanceState; import org.jclouds.ec2.domain.InstanceState;
import org.jclouds.ec2.domain.InstanceType; import org.jclouds.ec2.domain.InstanceType;
import org.jclouds.ec2.domain.IpProtocol; import org.jclouds.ec2.domain.IpProtocol;
@ -49,8 +51,6 @@ import org.jclouds.ec2.domain.RootDeviceType;
import org.jclouds.ec2.domain.RunningInstance; import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.ec2.domain.Snapshot; import org.jclouds.ec2.domain.Snapshot;
import org.jclouds.ec2.domain.Volume; import org.jclouds.ec2.domain.Volume;
import org.jclouds.ec2.domain.Image.Architecture;
import org.jclouds.ec2.domain.Image.ImageType;
import org.jclouds.ec2.domain.Volume.InstanceInitiatedShutdownBehavior; import org.jclouds.ec2.domain.Volume.InstanceInitiatedShutdownBehavior;
import org.jclouds.ec2.predicates.InstanceStateRunning; import org.jclouds.ec2.predicates.InstanceStateRunning;
import org.jclouds.ec2.predicates.InstanceStateStopped; import org.jclouds.ec2.predicates.InstanceStateStopped;
@ -65,9 +65,8 @@ import org.jclouds.net.IPSocket;
import org.jclouds.predicates.RetryablePredicate; import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.predicates.SocketOpen; import org.jclouds.predicates.SocketOpen;
import org.jclouds.rest.RestContextFactory; import org.jclouds.rest.RestContextFactory;
import org.jclouds.scriptbuilder.InitBuilder; import org.jclouds.scriptbuilder.InitScript;
import org.jclouds.scriptbuilder.domain.OsFamily; import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.Statements; import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshClient;
import org.jclouds.ssh.SshException; import org.jclouds.ssh.SshException;
@ -77,7 +76,6 @@ import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
@ -256,12 +254,12 @@ public class EBSBootEC2ClientLiveTest extends BaseVersionedServiceLiveTest {
@BeforeTest @BeforeTest
void makeScript() { void makeScript() {
mkEbsBoot = new InitBuilder( mkEbsBoot = InitScript.builder()
"mkebsboot",// name of the script .name("mkebsboot")
"/tmp",// working directory .home("/tmp")
"/tmp/logs",// location of stdout.log and stderr.log .logDir("/tmp/logs")
ImmutableMap.of("imageDir", "/mnt/tmp", "ebsDevice", "/dev/sdh", "ebsMountPoint", "/mnt/ebs"), .exportVariables(ImmutableMap.of("imageDir", "/mnt/tmp", "ebsDevice", "/dev/sdh", "ebsMountPoint", "/mnt/ebs"))
ImmutableList.<Statement> of(Statements .run(Statements
.interpret( .interpret(
"echo creating a filesystem and mounting the ebs volume", "echo creating a filesystem and mounting the ebs volume",
"{md} {varl}IMAGE_DIR{varr} {varl}EBS_MOUNT_POINT{varr}", "{md} {varl}IMAGE_DIR{varr} {varl}EBS_MOUNT_POINT{varr}",
@ -275,7 +273,7 @@ public class EBSBootEC2ClientLiveTest extends BaseVersionedServiceLiveTest {
"echo copying the local working copy to the ebs mount", "{cd} {varl}IMAGE_DIR{varr}", "echo copying the local working copy to the ebs mount", "{cd} {varl}IMAGE_DIR{varr}",
"tar -cSf - * | tar xf - -C {varl}EBS_MOUNT_POINT{varr}", "echo size of ebs", "tar -cSf - * | tar xf - -C {varl}EBS_MOUNT_POINT{varr}", "echo size of ebs",
"du -sk {varl}EBS_MOUNT_POINT{varr}", "echo size of source", "du -sk {varl}IMAGE_DIR{varr}", "du -sk {varl}EBS_MOUNT_POINT{varr}", "echo size of source", "du -sk {varl}IMAGE_DIR{varr}",
"rm -rf {varl}IMAGE_DIR{varr}/*", "umount {varl}EBS_MOUNT_POINT{varr}", "echo " + SCRIPT_END))) "rm -rf {varl}IMAGE_DIR{varr}/*", "umount {varl}EBS_MOUNT_POINT{varr}", "echo " + SCRIPT_END)).build()
.render(OsFamily.UNIX); .render(OsFamily.UNIX);
} }

View File

@ -28,7 +28,7 @@ import java.io.IOException;
import java.net.URI; import java.net.URI;
import org.jclouds.compute.domain.OperatingSystem; import org.jclouds.compute.domain.OperatingSystem;
import org.jclouds.scriptbuilder.InitBuilder; import org.jclouds.scriptbuilder.InitScript;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.StatementList; import org.jclouds.scriptbuilder.domain.StatementList;
import org.jclouds.scriptbuilder.statements.java.InstallJDK; import org.jclouds.scriptbuilder.statements.java.InstallJDK;
@ -71,15 +71,13 @@ public class RunScriptData {
} }
// NOTE do not name this the same as your login user, or the init process may kill you! // NOTE do not name this the same as your login user, or the init process may kill you!
public static InitBuilder startJBoss(String configuration) { public static InitScript startJBoss(String configuration) {
return new InitBuilder( return InitScript.builder()
"jboss", .name("jboss")
JBOSS_HOME, .home(JBOSS_HOME)
JBOSS_HOME, .exportVariables(ImmutableMap.of("jbossHome", JBOSS_HOME))
ImmutableMap.of("jbossHome", JBOSS_HOME), .init(appendFile(JBOSS_HOME + "/standalone/configuration/standalone-custom.xml", Splitter.on('\n').split(configuration)))
ImmutableList.<Statement>of(appendFile(JBOSS_HOME + "/standalone/configuration/standalone-custom.xml", Splitter.on('\n').split(configuration))), .run(interpret(new StringBuilder().append("java ").append(' ')
ImmutableList
.<Statement> of(interpret(new StringBuilder().append("java ").append(' ')
.append("-server -Xms128m -Xmx128m -XX:MaxPermSize=128m -Djava.net.preferIPv4Stack=true -XX:+UseFastAccessorMethods -XX:+TieredCompilation -Xverify:none -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000").append(' ') .append("-server -Xms128m -Xmx128m -XX:MaxPermSize=128m -Djava.net.preferIPv4Stack=true -XX:+UseFastAccessorMethods -XX:+TieredCompilation -Xverify:none -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000").append(' ')
.append("-Djboss.modules.system.pkgs=org.jboss.byteman").append(' ') .append("-Djboss.modules.system.pkgs=org.jboss.byteman").append(' ')
.append("-Dorg.jboss.boot.log.file=$JBOSS_HOME/standalone/log/boot.log").append(' ') .append("-Dorg.jboss.boot.log.file=$JBOSS_HOME/standalone/log/boot.log").append(' ')
@ -91,7 +89,7 @@ public class RunScriptData {
.append("org.jboss.as.standalone").append(' ') .append("org.jboss.as.standalone").append(' ')
.append("-Djboss.home.dir=$JBOSS_HOME").append(' ') .append("-Djboss.home.dir=$JBOSS_HOME").append(' ')
.append("--server-config=standalone-custom.xml") .append("--server-config=standalone-custom.xml")
.toString()))); .toString())).build();
} }
// TODO make this a cli option // TODO make this a cli option

View File

@ -21,6 +21,7 @@ package org.jclouds.compute.callables;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Date; import java.util.Date;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -30,22 +31,28 @@ import javax.annotation.Resource;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.compute.domain.ExecResponse; import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.events.StatementOnNodeCompletion;
import org.jclouds.compute.events.StatementOnNodeFailure;
import org.jclouds.compute.predicates.ScriptStatusReturnsZero; import org.jclouds.compute.predicates.ScriptStatusReturnsZero;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.predicates.RetryablePredicate; import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.scriptbuilder.InitBuilder; import org.jclouds.scriptbuilder.InitScript;
import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshClient;
import com.google.common.base.Objects;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import com.google.common.eventbus.EventBus;
import com.google.common.primitives.Ints;
import com.google.common.util.concurrent.AbstractFuture; import com.google.common.util.concurrent.AbstractFuture;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
import com.google.inject.name.Named; import com.google.inject.name.Named;
/** /**
* A future that works in tandem with a task that was invoked by {@link InitBuilder} * A future that works in tandem with a task that was invoked by
* {@link InitScript}
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@ -60,23 +67,31 @@ public class BlockUntilInitScriptStatusIsZeroThenReturnOutput extends AbstractFu
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
private final ExecutorService userThreads; private final ExecutorService userThreads;
private final EventBus eventBus;
private final SudoAwareInitManager commandRunner; private final SudoAwareInitManager commandRunner;
private final RetryablePredicate<String> notRunningAnymore;
private boolean shouldCancel; public SudoAwareInitManager getCommandRunner() {
return commandRunner;
}
private final RetryablePredicate<String> notRunningAnymore;
@Inject @Inject
public BlockUntilInitScriptStatusIsZeroThenReturnOutput( public BlockUntilInitScriptStatusIsZeroThenReturnOutput(
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads, EventBus eventBus,
ComputeServiceConstants.InitStatusProperties properties, ComputeServiceConstants.InitStatusProperties properties, final ScriptStatusReturnsZero stateRunning,
final ScriptStatusReturnsZero stateRunning, @Assisted final SudoAwareInitManager commandRunner) { @Assisted final SudoAwareInitManager commandRunner) {
long retryMaxWait = TimeUnit.DAYS.toMillis(365); // arbitrarily high value, but Long.MAX_VALUE doesn't work! long retryMaxWait = TimeUnit.DAYS.toMillis(365); // arbitrarily high
// value, but
// Long.MAX_VALUE doesn't
// work!
long retryInitialPeriod = properties.initStatusInitialPeriod; long retryInitialPeriod = properties.initStatusInitialPeriod;
long retryMaxPeriod = properties.initStatusMaxPeriod; long retryMaxPeriod = properties.initStatusMaxPeriod;
this.commandRunner = checkNotNull(commandRunner, "commandRunner"); this.commandRunner = checkNotNull(commandRunner, "commandRunner");
this.userThreads = checkNotNull(userThreads, "userThreads"); this.userThreads = checkNotNull(userThreads, "userThreads");
this.eventBus = checkNotNull(eventBus, "eventBus");
this.notRunningAnymore = new RetryablePredicate<String>(new Predicate<String>() { this.notRunningAnymore = new RetryablePredicate<String>(new Predicate<String>() {
@Override @Override
@ -85,13 +100,13 @@ public class BlockUntilInitScriptStatusIsZeroThenReturnOutput extends AbstractFu
} }
}, retryMaxWait, retryInitialPeriod, retryMaxPeriod, TimeUnit.MILLISECONDS) { }, retryMaxWait, retryInitialPeriod, retryMaxPeriod, TimeUnit.MILLISECONDS) {
/** /**
* make sure we stop the retry loop if someone cancelled the future, this keeps threads * make sure we stop the retry loop if someone cancelled the future,
* from being consumed on dead tasks * this keeps threads from being consumed on dead tasks
*/ */
@Override @Override
protected boolean atOrAfter(Date end) { protected boolean atOrAfter(Date end) {
if (shouldCancel) if (isCancelled())
Throwables.propagate(new TimeoutException("cancelled")); Throwables.propagate(new CancellationException("cancelled"));
return super.atOrAfter(end); return super.atOrAfter(end);
} }
}; };
@ -105,20 +120,28 @@ public class BlockUntilInitScriptStatusIsZeroThenReturnOutput extends AbstractFu
} }
/** /**
* Submits a thread that will either set the result of the future or the exception that took * Submits a thread that will either set the result of the future or the
* place * exception that took place
*/ */
public BlockUntilInitScriptStatusIsZeroThenReturnOutput init() { public BlockUntilInitScriptStatusIsZeroThenReturnOutput init() {
userThreads.submit(new Runnable() { userThreads.submit(new Runnable() {
@Override @Override
public void run() { public void run() {
try { try {
boolean complete = notRunningAnymore.apply("status"); notRunningAnymore.apply("status");
String stdout = commandRunner.runAction("tail").getOutput(); String stdout = commandRunner.runAction("stdout").getOutput();
String stderr = commandRunner.runAction("tailerr").getOutput(); String stderr = commandRunner.runAction("stderr").getOutput();
// TODO make ScriptBuilder save exit status on nuhup Integer exitStatus = Ints.tryParse(commandRunner.runAction("exitstatus").getOutput().trim());
logger.debug("<< complete(%s) status(%s)", commandRunner.getStatement().getInstanceName(), complete); ExecResponse exec = new ExecResponse(stdout, stderr, exitStatus == null ? -1 : exitStatus);
set(new ExecResponse(stdout, stderr, complete && !shouldCancel ? 0 : -1)); if (exitStatus == null) {
Integer pid = Ints.tryParse(commandRunner.runAction("status").getOutput().trim());
throw new ScriptStillRunningException(String.format("%s still running: pid(%s), last status: %s",
BlockUntilInitScriptStatusIsZeroThenReturnOutput.this, pid, exec),
BlockUntilInitScriptStatusIsZeroThenReturnOutput.this);
}
logger.debug("<< complete(%s) status(%s)", commandRunner.getStatement().getInstanceName(), exitStatus);
set(exec);
} catch (CancellationException e) {
} catch (Exception e) { } catch (Exception e) {
setException(e); setException(e);
} }
@ -127,72 +150,54 @@ public class BlockUntilInitScriptStatusIsZeroThenReturnOutput extends AbstractFu
return this; return this;
} }
@Override
protected boolean set(ExecResponse value) {
eventBus.post(new StatementOnNodeCompletion(getCommandRunner().getStatement(), getCommandRunner().getNode(),
value));
return super.set(value);
}
@Override @Override
protected void interruptTask() { protected void interruptTask() {
logger.debug("<< cancelled(%s)", commandRunner.getStatement().getInstanceName()); logger.debug("<< cancelled(%s)", commandRunner.getStatement().getInstanceName());
commandRunner.refreshAndRunAction("stop"); ExecResponse returnVal = commandRunner.refreshAndRunAction("stop");
shouldCancel = true; CancellationException e = new CancellationException(String.format(
"cancelled %s on node: %s; stop command had exit status: %s", getCommandRunner().getStatement()
.getInstanceName(), getCommandRunner().getNode().getId(), returnVal));
eventBus.post(new StatementOnNodeFailure(getCommandRunner().getStatement(), getCommandRunner().getNode(), e));
super.interruptTask(); super.interruptTask();
} }
@Override @Override
public String toString() { public String toString() {
return String.format("running task[%s]", commandRunner); return Objects.toStringHelper(this).add("commandRunner", commandRunner).toString();
} }
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; return Objects.hashCode(commandRunner);
int result = 1;
result = prime * result + ((commandRunner == null) ? 0 : commandRunner.hashCode());
result = prime * result + ((logger == null) ? 0 : logger.hashCode());
result = prime * result + ((notRunningAnymore == null) ? 0 : notRunningAnymore.hashCode());
result = prime * result + (shouldCancel ? 1231 : 1237);
result = prime * result + ((userThreads == null) ? 0 : userThreads.hashCode());
return result;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object o) {
if (this == obj) if (o == null)
return true;
if (obj == null)
return false; return false;
if (getClass() != obj.getClass()) if (!o.getClass().equals(getClass()))
return false; return false;
BlockUntilInitScriptStatusIsZeroThenReturnOutput other = (BlockUntilInitScriptStatusIsZeroThenReturnOutput) obj; BlockUntilInitScriptStatusIsZeroThenReturnOutput that = BlockUntilInitScriptStatusIsZeroThenReturnOutput.class
if (commandRunner == null) { .cast(o);
if (other.commandRunner != null) return Objects.equal(this.commandRunner, that.commandRunner);
return false;
} else if (!commandRunner.equals(other.commandRunner))
return false;
if (logger == null) {
if (other.logger != null)
return false;
} else if (!logger.equals(other.logger))
return false;
if (notRunningAnymore == null) {
if (other.notRunningAnymore != null)
return false;
} else if (!notRunningAnymore.equals(other.notRunningAnymore))
return false;
if (shouldCancel != other.shouldCancel)
return false;
if (userThreads == null) {
if (other.userThreads != null)
return false;
} else if (!userThreads.equals(other.userThreads))
return false;
return true;
} }
@Override @Override
public ExecResponse get(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException, public ExecResponse get(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException,
ExecutionException { ExecutionException {
try { try {
return super.get(timeout, unit); return super.get(timeout, unit);
} catch (TimeoutException e) { } catch (TimeoutException e) {
throw new ScriptStillRunningException(timeout, unit, this); ScriptStillRunningException exception = new ScriptStillRunningException(timeout, unit, this);
exception.initCause(e);
throw exception;
} }
} }

View File

@ -26,7 +26,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.scriptbuilder.InitBuilder; import org.jclouds.scriptbuilder.InitScript;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.inject.Inject; import com.google.inject.Inject;
@ -104,8 +104,8 @@ public class InitScriptConfigurationForTasks {
* *
* @return the naming convention of init scripts. ex. {@code /tmp/init-%s}, noting logs are under * @return the naming convention of init scripts. ex. {@code /tmp/init-%s}, noting logs are under
* the basedir/%s where %s is the taskName * the basedir/%s where %s is the taskName
* @see InitBuilder#getHomeDir * @see InitScript#getHomeDir
* @see InitBuilder#getLogDir * @see InitScript#getLogDir
*/ */
public String getInitScriptPattern() { public String getInitScriptPattern() {
return initScriptPattern; return initScriptPattern;

View File

@ -21,19 +21,15 @@ package org.jclouds.compute.callables;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import java.util.Collections;
import javax.annotation.Resource;
import javax.inject.Named;
import org.jclouds.compute.domain.ExecResponse; import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder; import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.events.InitScriptOnNodeSubmission;
import org.jclouds.compute.events.StatementOnNodeCompletion;
import org.jclouds.compute.events.StatementOnNodeFailure;
import org.jclouds.compute.options.RunScriptOptions; import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.LoginCredentials; import org.jclouds.domain.LoginCredentials;
import org.jclouds.logging.Logger; import org.jclouds.scriptbuilder.InitScript;
import org.jclouds.scriptbuilder.InitBuilder;
import org.jclouds.scriptbuilder.domain.AdminAccessVisitor; import org.jclouds.scriptbuilder.domain.AdminAccessVisitor;
import org.jclouds.scriptbuilder.domain.AppendFile; import org.jclouds.scriptbuilder.domain.AppendFile;
import org.jclouds.scriptbuilder.domain.OsFamily; import org.jclouds.scriptbuilder.domain.OsFamily;
@ -45,6 +41,8 @@ import org.jclouds.ssh.SshException;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.base.Throwables;
import com.google.common.eventbus.EventBus;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject; import com.google.inject.assistedinject.AssistedInject;
@ -53,28 +51,18 @@ import com.google.inject.assistedinject.AssistedInject;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class RunScriptOnNodeAsInitScriptUsingSsh extends SudoAwareInitManager implements RunScriptOnNode { public class RunScriptOnNodeAsInitScriptUsingSsh extends SudoAwareInitManager implements RunScriptOnNode {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
protected final String initFile; protected final EventBus eventBus;
/**
* @return the absolute path to the file on disk relating to this task.
*/
public String getInitFile() {
return initFile;
}
@AssistedInject @AssistedInject
public RunScriptOnNodeAsInitScriptUsingSsh(Function<NodeMetadata, SshClient> sshFactory, public RunScriptOnNodeAsInitScriptUsingSsh(Function<NodeMetadata, SshClient> sshFactory, EventBus eventBus,
InitScriptConfigurationForTasks initScriptConfiguration, @Assisted NodeMetadata node, InitScriptConfigurationForTasks initScriptConfiguration, @Assisted NodeMetadata node,
@Assisted Statement script, @Assisted RunScriptOptions options) { @Assisted Statement script, @Assisted RunScriptOptions options) {
super(sshFactory, options.shouldRunAsRoot(), checkNotNull(node, "node"), super(sshFactory, options.shouldRunAsRoot(), checkNotNull(node, "node"),
checkNotNull(script, "script") instanceof InitBuilder ? InitBuilder.class.cast(script) initScriptConfiguration, checkNotNull(script, "script") instanceof InitScript ? InitScript.class.cast(script)
: createInitScript(checkNotNull(initScriptConfiguration, "initScriptConfiguration"), options : createInitScript(checkNotNull(initScriptConfiguration, "initScriptConfiguration"), options
.getTaskName(), script)); .getTaskName(), script));
this.initFile = String.format(initScriptConfiguration.getInitScriptPattern(), init.getInstanceName()); this.eventBus = checkNotNull(eventBus, "eventBus");
} }
@Override @Override
@ -88,19 +76,20 @@ public class RunScriptOnNodeAsInitScriptUsingSsh extends SudoAwareInitManager im
checkState(ssh != null, "please call init() before invoking call"); checkState(ssh != null, "please call init() before invoking call");
try { try {
ssh.connect(); ssh.connect();
return doCall(); ExecResponse returnVal = doCall();
eventBus.post(new StatementOnNodeCompletion(init, node, returnVal));
return returnVal;
} finally { } finally {
if (ssh != null) if (ssh != null)
ssh.disconnect(); ssh.disconnect();
} }
} }
public static InitBuilder createInitScript(InitScriptConfigurationForTasks config, String name, Statement script) { public static InitScript createInitScript(InitScriptConfigurationForTasks config, String name, Statement script) {
if (name == null) { if (name == null) {
name = "jclouds-script-" + config.getAnonymousTaskSuffixSupplier().get(); name = "jclouds-script-" + config.getAnonymousTaskSuffixSupplier().get();
} }
return new InitBuilder(name, config.getBasedir() + "/" + name, config.getBasedir() + "/" + name, Collections return InitScript.builder().name(name).home(config.getBasedir() + "/" + name).run(script).build();
.<String, String> emptyMap(), Collections.singleton(script));
} }
protected void refreshSshIfNewAdminCredentialsConfigured(AdminAccess input) { protected void refreshSshIfNewAdminCredentialsConfigured(AdminAccess input) {
@ -115,34 +104,41 @@ public class RunScriptOnNodeAsInitScriptUsingSsh extends SudoAwareInitManager im
} }
protected ExecResponse doCall() { protected ExecResponse doCall() {
eventBus.post(new InitScriptOnNodeSubmission(init, node));
try { try {
ssh.put(initFile, init.render(OsFamily.UNIX)); try {
} catch (SshException e) { ssh.put(initFile, init.render(OsFamily.UNIX));
// If there's a problem with the sftp configuration, we can try via ssh exec } catch (SshException e) {
if (logger.isTraceEnabled()) // If there's a problem with the sftp configuration, we can try via
logger.warn(e, "<< (%s) problem using sftp [%s], attempting via sshexec", ssh.toString(), e.getMessage()); // ssh exec
else if (logger.isTraceEnabled())
logger.warn("<< (%s) problem using sftp [%s], attempting via sshexec", ssh.toString(), e.getMessage()); logger.warn(e, "<< (%s) problem using sftp [%s], attempting via sshexec", ssh.toString(), e.getMessage());
ssh.disconnect(); else
ssh.connect(); logger.warn("<< (%s) problem using sftp [%s], attempting via sshexec", ssh.toString(), e.getMessage());
ssh.exec("rm " + initFile); ssh.disconnect();
ssh.exec(Statements.appendFile(initFile, Splitter.on('\n').split(init.render(OsFamily.UNIX)), ssh.connect();
AppendFile.MARKER + "_" + init.getInstanceName()).render(OsFamily.UNIX)); ssh.exec("rm " + initFile);
} ssh.exec(Statements.appendFile(initFile, Splitter.on('\n').split(init.render(OsFamily.UNIX)),
AppendFile.DELIMETER + "_" + init.getInstanceName()).render(OsFamily.UNIX));
ssh.exec("chmod 755 " + initFile);
setupLinkToInitFile();
runAction("init");
init.getInitStatement().accept(new AdminAccessVisitor() {
@Override
public void visit(AdminAccess input) {
refreshSshIfNewAdminCredentialsConfigured(input);
} }
}); ssh.exec("chmod 755 " + initFile);
return runAction("start"); setupLinkToInitFile();
runAction("init");
init.getInitStatement().accept(new AdminAccessVisitor() {
@Override
public void visit(AdminAccess input) {
refreshSshIfNewAdminCredentialsConfigured(input);
}
});
return runAction("start");
} catch (Throwable e) {
eventBus.post(new StatementOnNodeFailure(init, node, e));
throw Throwables.propagate(e);
}
} }
protected void setupLinkToInitFile() { protected void setupLinkToInitFile() {

View File

@ -19,7 +19,6 @@
package org.jclouds.compute.callables; package org.jclouds.compute.callables;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -27,6 +26,7 @@ import javax.inject.Inject;
import org.jclouds.compute.domain.ExecResponse; import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.events.StatementOnNodeFailure;
import org.jclouds.compute.options.RunScriptOptions; import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
@ -34,6 +34,7 @@ import org.jclouds.ssh.SshClient;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import com.google.common.eventbus.EventBus;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
/** /**
@ -46,10 +47,11 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete extends Ru
@Inject @Inject
public RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete( public RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete(
BlockUntilInitScriptStatusIsZeroThenReturnOutput.Factory statusFactory, Timeouts timeouts, BlockUntilInitScriptStatusIsZeroThenReturnOutput.Factory statusFactory, Timeouts timeouts,
Function<NodeMetadata, SshClient> sshFactory, InitScriptConfigurationForTasks initScriptConfiguration, Function<NodeMetadata, SshClient> sshFactory, EventBus eventBus,
@Assisted NodeMetadata node, @Assisted Statement script, @Assisted RunScriptOptions options) { InitScriptConfigurationForTasks initScriptConfiguration, @Assisted NodeMetadata node,
super(sshFactory, initScriptConfiguration, node, script, options); @Assisted Statement script, @Assisted RunScriptOptions options) {
super(sshFactory, eventBus, initScriptConfiguration, node, script, options);
this.statusFactory = checkNotNull(statusFactory, "statusFactory"); this.statusFactory = checkNotNull(statusFactory, "statusFactory");
this.timeouts = checkNotNull(timeouts, "timeouts"); this.timeouts = checkNotNull(timeouts, "timeouts");
} }
@ -58,16 +60,21 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete extends Ru
public ExecResponse doCall() { public ExecResponse doCall() {
try { try {
return future().get(timeouts.scriptComplete, TimeUnit.MILLISECONDS); return future().get(timeouts.scriptComplete, TimeUnit.MILLISECONDS);
} catch (Exception e) { } catch (Throwable e) {
Throwables.propagate(e); eventBus.post(new StatementOnNodeFailure(init, node, e));
return null; throw Throwables.propagate(e);
} }
} }
public BlockUntilInitScriptStatusIsZeroThenReturnOutput future() { public BlockUntilInitScriptStatusIsZeroThenReturnOutput future() {
ExecResponse returnVal = super.doCall(); ExecResponse returnVal = super.doCall();
checkState(returnVal.getExitCode() == 0, String.format("task: %s had non-zero exit status: %s", init if (returnVal.getExitStatus() != 0) {
.getInstanceName(), returnVal)); IllegalStateException e = new IllegalStateException(String.format(
"instance: %s on node: %s had non-zero exit status: %s", init.getInstanceName(), getNode().getId(),
returnVal));
eventBus.post(new StatementOnNodeFailure(init, node, e));
throw e;
}
return statusFactory.create(this).init(); return statusFactory.create(this).init();
} }

View File

@ -26,6 +26,9 @@ import javax.inject.Named;
import org.jclouds.compute.domain.ExecResponse; import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.events.StatementOnNodeFailure;
import org.jclouds.compute.events.StatementOnNodeCompletion;
import org.jclouds.compute.events.StatementOnNodeSubmission;
import org.jclouds.compute.options.RunScriptOptions; import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
@ -36,6 +39,8 @@ import org.jclouds.ssh.SshClient;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.base.Throwables;
import com.google.common.eventbus.EventBus;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject; import com.google.inject.assistedinject.AssistedInject;
@ -51,6 +56,7 @@ public class RunScriptOnNodeUsingSsh implements RunScriptOnNode {
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
protected final Function<NodeMetadata, SshClient> sshFactory; protected final Function<NodeMetadata, SshClient> sshFactory;
protected final EventBus eventBus;
protected final NodeMetadata node; protected final NodeMetadata node;
protected final Statement statement; protected final Statement statement;
protected final boolean runAsRoot; protected final boolean runAsRoot;
@ -58,9 +64,10 @@ public class RunScriptOnNodeUsingSsh implements RunScriptOnNode {
protected SshClient ssh; protected SshClient ssh;
@AssistedInject @AssistedInject
public RunScriptOnNodeUsingSsh(Function<NodeMetadata, SshClient> sshFactory, @Assisted NodeMetadata node, public RunScriptOnNodeUsingSsh(Function<NodeMetadata, SshClient> sshFactory, EventBus eventBus,
@Assisted Statement statement, @Assisted RunScriptOptions options) { @Assisted NodeMetadata node, @Assisted Statement statement, @Assisted RunScriptOptions options) {
this.sshFactory = checkNotNull(sshFactory, "sshFactory"); this.sshFactory = checkNotNull(sshFactory, "sshFactory");
this.eventBus = checkNotNull(eventBus, "eventBus");
this.node = checkNotNull(node, "node"); this.node = checkNotNull(node, "node");
this.statement = checkNotNull(statement, "statement"); this.statement = checkNotNull(statement, "statement");
this.runAsRoot = options.shouldRunAsRoot(); this.runAsRoot = options.shouldRunAsRoot();
@ -72,13 +79,20 @@ public class RunScriptOnNodeUsingSsh implements RunScriptOnNode {
try { try {
ssh.connect(); ssh.connect();
ExecResponse returnVal; ExecResponse returnVal;
eventBus.post(new StatementOnNodeSubmission(statement, node));
String command = (runAsRoot) ? execAsRoot(statement.render(OsFamily.UNIX)) : execScriptAsDefaultUser(statement String command = (runAsRoot) ? execAsRoot(statement.render(OsFamily.UNIX)) : execScriptAsDefaultUser(statement
.render(OsFamily.UNIX)); .render(OsFamily.UNIX));
returnVal = runCommand(command); try {
returnVal = runCommand(command);
} catch (Throwable e) {
eventBus.post(new StatementOnNodeFailure(statement, node, e));
throw Throwables.propagate(e);
}
eventBus.post(new StatementOnNodeCompletion(statement, node, returnVal));
if (logger.isTraceEnabled()) if (logger.isTraceEnabled())
logger.trace("<< %s[%s]", statement, returnVal); logger.trace("<< %s[%s]", statement, returnVal);
else else
logger.debug("<< %s(%d)", statement, returnVal.getExitCode()); logger.debug("<< %s(%d)", statement, returnVal.getExitStatus());
return returnVal; return returnVal;
} finally { } finally {
if (ssh != null) if (ssh != null)

View File

@ -28,7 +28,7 @@ import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.scriptbuilder.InitBuilder; import org.jclouds.scriptbuilder.InitScript;
import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshClient;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
@ -47,16 +47,25 @@ public class SudoAwareInitManager {
protected Logger computeLogger = Logger.NULL; protected Logger computeLogger = Logger.NULL;
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
protected NodeMetadata node; protected NodeMetadata node;
protected final InitBuilder init; protected final String initFile;
protected final InitScript init;
protected final boolean runAsRoot; protected final boolean runAsRoot;
protected final Function<NodeMetadata, SshClient> sshFactory; protected final Function<NodeMetadata, SshClient> sshFactory;
protected SshClient ssh; protected SshClient ssh;
/**
* @return the absolute path to the file on disk relating to this task.
*/
public String getInitFile() {
return initFile;
}
public SudoAwareInitManager(Function<NodeMetadata, SshClient> sshFactory, boolean runAsRoot, NodeMetadata node, public SudoAwareInitManager(Function<NodeMetadata, SshClient> sshFactory, boolean runAsRoot, NodeMetadata node,
InitBuilder init) { InitScriptConfigurationForTasks initScriptConfiguration, InitScript init) {
this.sshFactory = checkNotNull(sshFactory, "sshFactory"); this.sshFactory = checkNotNull(sshFactory, "sshFactory");
this.runAsRoot = runAsRoot; this.runAsRoot = runAsRoot;
this.node = checkNotNull(node, "node"); this.node = checkNotNull(node, "node");
this.initFile = String.format(initScriptConfiguration.getInitScriptPattern(), init.getInstanceName());
this.init = checkNotNull(init, "init"); this.init = checkNotNull(init, "init");
} }
@ -82,41 +91,44 @@ public class SudoAwareInitManager {
: execScriptAsDefaultUser(action); : execScriptAsDefaultUser(action);
returnVal = runCommand(command); returnVal = runCommand(command);
if ("status".equals(action)) if ("status".equals(action))
logger.trace("<< %s(%d)", action, returnVal.getExitCode()); logger.trace("<< %s(%d)", action, returnVal.getExitStatus());
else if (computeLogger.isTraceEnabled()) else if (computeLogger.isTraceEnabled())
computeLogger.trace("<< %s[%s]", action, returnVal); computeLogger.trace("<< %s[%s]", action, returnVal);
else else
computeLogger.debug("<< %s(%d)", action, returnVal.getExitCode()); computeLogger.debug("<< %s(%d)", action, returnVal.getExitStatus());
return returnVal; return returnVal;
} }
ExecResponse runCommand(String command) { ExecResponse runCommand(String command) {
String statement = String.format(">> running [%s] as %s@%s", command.replace( String statement = String.format("[%s] as %s@%s", command.replace(
node.getCredentials().getPassword() != null ? node.getCredentials().getPassword() : "XXXXX", "XXXXX"), ssh node.getCredentials().getPassword() != null ? node.getCredentials().getPassword() : "XXXXX", "XXXXX"), ssh
.getUsername(), ssh.getHostAddress()); .getUsername(), ssh.getHostAddress());
if (command.endsWith("status")) if (command.endsWith("status"))
logger.trace(statement); logger.trace(">> running " + statement);
else else
computeLogger.debug(statement); computeLogger.debug(">> running " + statement);
return ssh.exec(command); ExecResponse returnVal = ssh.exec(command);
if (!command.endsWith("status"))
checkState(returnVal.getExitStatus() == 0, "error running %s; returnVal !=0: %s", statement, returnVal);
return returnVal;
} }
@VisibleForTesting @VisibleForTesting
String execScriptAsRoot(String action) { String execScriptAsRoot(String action) {
String command; String command;
if (node.getCredentials().identity.equals("root")) { if (node.getCredentials().identity.equals("root")) {
command = "./" + init.getInstanceName() + " " + action; command = initFile + " " + action;
} else if (node.getCredentials().shouldAuthenticateSudo()) { } else if (node.getCredentials().shouldAuthenticateSudo()) {
command = String.format("echo '%s'|sudo -S ./%s %s", node.getCredentials().getPassword(), command = String.format("echo '%s'|sudo -S %s %s", node.getCredentials().getPassword(),
init.getInstanceName(), action); initFile, action);
} else { } else {
command = "sudo ./" + init.getInstanceName() + " " + action; command = "sudo " + initFile + " " + action;
} }
return command; return command;
} }
protected String execScriptAsDefaultUser(String action) { protected String execScriptAsDefaultUser(String action) {
return "./" + init.getInstanceName() + " " + action; return initFile + " " + action;
} }
public NodeMetadata getNode() { public NodeMetadata getNode() {
@ -125,11 +137,11 @@ public class SudoAwareInitManager {
@Override @Override
public String toString() { public String toString() {
return Objects.toStringHelper(this).add("node", node).add("name", init.getInstanceName()) return Objects.toStringHelper(this).add("node", node.getId()).add("name", init.getInstanceName())
.add("runAsRoot", runAsRoot).toString(); .add("runAsRoot", runAsRoot).toString();
} }
public InitBuilder getStatement() { public InitScript getStatement() {
return init; return init;
} }
} }

View File

@ -20,19 +20,21 @@ package org.jclouds.compute.domain;
import org.jclouds.compute.config.CustomizationResponse; import org.jclouds.compute.config.CustomizationResponse;
import com.google.common.base.Objects;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
public class ExecResponse implements CustomizationResponse { public class ExecResponse implements CustomizationResponse {
private final String error;
private final String output; private final String output;
private final int exitCode; private final String error;
private final int exitStatus;
public ExecResponse(String output, String error, int exitCode) { public ExecResponse(String output, String error, int exitStatus) {
this.output = output; this.output = output;
this.error = error; this.error = error;
this.exitCode = exitCode; this.exitStatus = exitStatus;
} }
public String getError() { public String getError() {
@ -43,47 +45,38 @@ public class ExecResponse implements CustomizationResponse {
return output; return output;
} }
@Override /**
public String toString() { * @see #getExitStatus
return "[output=" + output + ", error=" + error + ", exitCode=" + exitCode + "]"; */
@Deprecated
public int getExitCode() {
return exitStatus;
}
public int getExitStatus() {
return exitStatus;
} }
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; return Objects.hashCode(output, error, exitStatus);
int result = 1;
result = prime * result + ((error == null) ? 0 : error.hashCode());
result = prime * result + exitCode;
result = prime * result + ((output == null) ? 0 : output.hashCode());
return result;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object o) {
if (this == obj) if (o == null)
return true;
if (obj == null)
return false; return false;
if (getClass() != obj.getClass()) if (!o.getClass().equals(getClass()))
return false; return false;
ExecResponse other = (ExecResponse) obj; ExecResponse that = ExecResponse.class.cast(o);
if (error == null) { return Objects.equal(this.output, that.output) && Objects.equal(this.error, that.error)
if (other.error != null) && Objects.equal(this.exitStatus, that.exitStatus);
return false;
} else if (!error.equals(other.error))
return false;
if (exitCode != other.exitCode)
return false;
if (output == null) {
if (other.output != null)
return false;
} else if (!output.equals(other.output))
return false;
return true;
} }
public int getExitCode() { @Override
return exitCode; public String toString() {
return Objects.toStringHelper("").add("output", output).add("error", error).add("exitStatus", exitStatus)
.toString();
} }
} }

View File

@ -220,7 +220,6 @@ public class NodeMetadataImpl extends ComputeMetadataImpl implements NodeMetadat
result = prime * result + ((imageId == null) ? 0 : imageId.hashCode()); result = prime * result + ((imageId == null) ? 0 : imageId.hashCode());
result = prime * result + ((hardware == null) ? 0 : hardware.hashCode()); result = prime * result + ((hardware == null) ? 0 : hardware.hashCode());
result = prime * result + ((os == null) ? 0 : os.hashCode()); result = prime * result + ((os == null) ? 0 : os.hashCode());
result = prime * result + ((credentials == null) ? 0 : credentials.hashCode());
return result; return result;
} }
@ -270,11 +269,6 @@ public class NodeMetadataImpl extends ComputeMetadataImpl implements NodeMetadat
return false; return false;
} else if (!os.equals(other.os)) } else if (!os.equals(other.os))
return false; return false;
if (credentials == null) {
if (other.credentials != null)
return false;
} else if (!credentials.equals(other.credentials))
return false;
return true; return true;
} }

View File

@ -0,0 +1,44 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you 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.compute.events;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.scriptbuilder.InitScript;
import com.google.common.annotations.Beta;
/**
* An init script was submitted to a node for exectuion.
* <p/>
* Note this does not guarantee that there was success, nor that the init script started.
*
* @author Adrian Cole
*/
@Beta
public class InitScriptOnNodeSubmission extends StatementOnNodeSubmission {
public InitScriptOnNodeSubmission(InitScript statement, NodeMetadata node) {
super(statement, node);
}
public InitScript getStatement() {
return InitScript.class.cast(statement);
}
}

View File

@ -0,0 +1,76 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you 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.compute.events;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.scriptbuilder.domain.Statement;
import com.google.common.annotations.Beta;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
/**
* @author Adrian Cole
*/
@Beta
public class StatementOnNode {
protected final Statement statement;
protected final NodeMetadata node;
public StatementOnNode(Statement statement, NodeMetadata node) {
this.statement = checkNotNull(statement, "statement");
this.node = checkNotNull(node, "node");
}
public Statement getStatement() {
return statement;
}
public NodeMetadata getNode() {
return node;
}
@Override
public int hashCode() {
return Objects.hashCode(statement, node);
}
@Override
public boolean equals(Object o) {
if (o == null)
return false;
if (!o.getClass().equals(getClass()))
return false;
StatementOnNode that = StatementOnNode.class.cast(o);
return Objects.equal(this.statement, that.statement) && Objects.equal(this.node, that.node);
}
@Override
public String toString() {
return string().toString();
}
protected ToStringHelper string() {
return Objects.toStringHelper(this).add("statement", statement).add("node", node.getId());
}
}

View File

@ -0,0 +1,53 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you 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.compute.events;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.scriptbuilder.domain.Statement;
import com.google.common.annotations.Beta;
import com.google.common.base.Objects.ToStringHelper;
/**
* A statement that completed execution on a node.
*
* @author Adrian Cole
*/
@Beta
public class StatementOnNodeCompletion extends StatementOnNode {
private final ExecResponse response;
public StatementOnNodeCompletion(Statement statement, NodeMetadata node, ExecResponse response) {
super(statement, node);
this.response = checkNotNull(response, "response");
}
public ExecResponse getResponse() {
return response;
}
@Override
protected ToStringHelper string() {
return super.string().add("response", response);
}
}

View File

@ -0,0 +1,52 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you 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.compute.events;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.scriptbuilder.domain.Statement;
import com.google.common.annotations.Beta;
import com.google.common.base.Objects.ToStringHelper;
/**
* A statement that failed execution on a node.
*
* @author Adrian Cole
*/
@Beta
public class StatementOnNodeFailure extends StatementOnNode {
private final Throwable cause;
public StatementOnNodeFailure(Statement statement, NodeMetadata node, Throwable cause) {
super(statement, node);
this.cause = checkNotNull(cause, "cause");
}
public Throwable getCause() {
return cause;
}
@Override
protected ToStringHelper string() {
return super.string().add("cause", cause.getMessage());
}
}

View File

@ -0,0 +1,41 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you 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.compute.events;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.scriptbuilder.domain.Statement;
import com.google.common.annotations.Beta;
/**
* A statement was submitted to a node for exectuion.
* <p/>
* Note this does not guarantee that there was success, nor that the node
* received the statement.
*
* @author Adrian Cole
*/
@Beta
public class StatementOnNodeSubmission extends StatementOnNode {
public StatementOnNodeSubmission(Statement statement, NodeMetadata node) {
super(statement, node);
}
}

View File

@ -25,7 +25,7 @@ import java.util.List;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.scriptbuilder.InitBuilder; import org.jclouds.scriptbuilder.InitScript;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.StatementList; import org.jclouds.scriptbuilder.domain.StatementList;
import org.jclouds.scriptbuilder.statements.ssh.AuthorizeRSAPublicKeys; import org.jclouds.scriptbuilder.statements.ssh.AuthorizeRSAPublicKeys;
@ -51,7 +51,7 @@ public class TemplateOptionsToStatement implements Function<TemplateOptions, Sta
if (options.getPrivateKey() != null) if (options.getPrivateKey() != null)
bootstrap.add(new InstallRSAPrivateKey(options.getPrivateKey())); bootstrap.add(new InstallRSAPrivateKey(options.getPrivateKey()));
if (bootstrap.size() >= 1) { if (bootstrap.size() >= 1) {
if (options.getTaskName() == null && !(options.getRunScript() instanceof InitBuilder)) if (options.getTaskName() == null && !(options.getRunScript() instanceof InitScript))
options.nameTask("bootstrap"); options.nameTask("bootstrap");
return bootstrap.size() == 1 ? bootstrap.get(0) : new StatementList(bootstrap); return bootstrap.size() == 1 ? bootstrap.get(0) : new StatementList(bootstrap);
} }

View File

@ -44,11 +44,11 @@ public class ScriptStatusReturnsZero implements Predicate<ScriptStatusReturnsZer
logger.trace("looking for [%s] state on %s@%s", commandUsingClient.command, commandUsingClient.client logger.trace("looking for [%s] state on %s@%s", commandUsingClient.command, commandUsingClient.client
.getUsername(), commandUsingClient.client.getHostAddress()); .getUsername(), commandUsingClient.client.getHostAddress());
ExecResponse response = refresh(commandUsingClient); ExecResponse response = refresh(commandUsingClient);
while (response.getExitCode() == -1) while (response.getExitStatus() == -1)
response = refresh(commandUsingClient); response = refresh(commandUsingClient);
logger.trace("%s@%s: looking for exit code 0: currently: %s", commandUsingClient.client.getUsername(), logger.trace("%s@%s: looking for exit code 0: currently: %s", commandUsingClient.client.getUsername(),
commandUsingClient.client.getHostAddress(), response.getExitCode()); commandUsingClient.client.getHostAddress(), response.getExitStatus());
return 0 == response.getExitCode(); return 0 == response.getExitStatus();
} }
private ExecResponse refresh(CommandUsingClient commandUsingClient) { private ExecResponse refresh(CommandUsingClient commandUsingClient) {

View File

@ -67,8 +67,8 @@ public class RunScriptOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements C
tainted = true; tainted = true;
try { try {
ExecResponse exec = runScriptOnNode.call(); ExecResponse exec = runScriptOnNode.call();
logger.trace("<< script output for node(%s): %s", runScriptOnNode.getNode().getId(), exec);
logger.debug("<< options applied node(%s)", runScriptOnNode.getNode().getId()); logger.debug("<< options applied node(%s)", runScriptOnNode.getNode().getId());
logger.trace("<< script output for node(%s): %s", runScriptOnNode.getNode().getId(), exec);
goodNodes.put(runScriptOnNode.getNode(), exec); goodNodes.put(runScriptOnNode.getNode(), exec);
return exec; return exec;
} catch (Exception e) { } catch (Exception e) {

View File

@ -50,7 +50,7 @@
(merge (merge
{:exit 0 :err "stderr" :out "stdout"} {:exit 0 :err "stderr" :out "stdout"}
(condp = cmd (condp = cmd
"./bootstrap status" {:exit 1 :out "[]"} "/tmp/init-bootstrap status" {:exit 1 :out "[]"}
{}))) {})))

View File

@ -256,7 +256,7 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
response = future.get(3, TimeUnit.MINUTES); response = future.get(3, TimeUnit.MINUTES);
assert response.getExitCode() == 0 : node.getId() + ": " + response; assert response.getExitStatus() == 0 : node.getId() + ": " + response;
node = client.getNodeMetadata(node.getId()); node = client.getNodeMetadata(node.getId());
// test that the node updated to the correct admin user! // test that the node updated to the correct admin user!
@ -265,7 +265,7 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
weCanCancelTasks(node); weCanCancelTasks(node);
assert response.getExitCode() == 0 : node.getId() + ": " + response; assert response.getExitStatus() == 0 : node.getId() + ": " + response;
response = client.runScriptOnNode(node.getId(), "echo $USER", wrapInInitScript(false).runAsRoot(false)); response = client.runScriptOnNode(node.getId(), "echo $USER", wrapInInitScript(false).runAsRoot(false));
@ -304,11 +304,11 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
assert false : node.getId() + ": " + response; assert false : node.getId() + ": " + response;
} catch (TimeoutException e) { } catch (TimeoutException e) {
assert !future.isDone(); assert !future.isDone();
response = client.runScriptOnNode(node.getId(), Statements.exec("./sleeper status"), wrapInInitScript(false) response = client.runScriptOnNode(node.getId(), Statements.exec("/tmp/init-sleeper status"), wrapInInitScript(false)
.runAsRoot(false)); .runAsRoot(false));
assert !response.getOutput().trim().equals("") : node.getId() + ": " + response; assert !response.getOutput().trim().equals("") : node.getId() + ": " + response;
future.cancel(true); future.cancel(true);
response = client.runScriptOnNode(node.getId(), Statements.exec("./sleeper status"), wrapInInitScript(false) response = client.runScriptOnNode(node.getId(), Statements.exec("/tmp/init-sleeper status"), wrapInInitScript(false)
.runAsRoot(false)); .runAsRoot(false));
assert response.getOutput().trim().equals("") : node.getId() + ": " + response; assert response.getOutput().trim().equals("") : node.getId() + ": " + response;
try { try {
@ -592,10 +592,10 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
IPSocket socket = new IPSocket(Iterables.get(node.getPublicAddresses(), 0), 8080); IPSocket socket = new IPSocket(Iterables.get(node.getPublicAddresses(), 0), 8080);
assert preciseSocketTester.apply(socket) : String.format("failed to open socket %s on node %s:%n%s%s", socket, assert preciseSocketTester.apply(socket) : String.format("failed to open socket %s on node %s:%n%s%s", socket,
node, init(node, processName, "tail"), init(node, processName, "tailerr")); node, init(node, processName, "stdout"), init(node, processName, "stderr"));
stats.socketOpenMilliseconds = watch.elapsedTime(TimeUnit.MILLISECONDS); stats.socketOpenMilliseconds = watch.elapsedTime(TimeUnit.MILLISECONDS);
exec = init(node, processName, "tail"); exec = init(node, processName, "stdout");
Matcher matcher = parseReported.matcher(exec.getOutput()); Matcher matcher = parseReported.matcher(exec.getOutput());
if (matcher.find()) if (matcher.find())
@ -606,7 +606,7 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
} }
public ExecResponse init(NodeMetadata node, String processName, String command) { public ExecResponse init(NodeMetadata node, String processName, String command) {
return client.runScriptOnNode(node.getId(), "./" + processName + " "+command, runAsRoot(false) return client.runScriptOnNode(node.getId(), "/tmp/init-" + processName + " "+command, runAsRoot(false)
.wrapInInitScript(false)); .wrapInInitScript(false));
} }
@ -716,13 +716,13 @@ public abstract class BaseComputeServiceLiveTest extends BaseVersionedServiceLiv
}), "jboss", node, JBOSS_PATTERN); }), "jboss", node, JBOSS_PATTERN);
client.runScriptOnNode(nodeId, "./jboss stop", runAsRoot(false).wrapInInitScript(false)); client.runScriptOnNode(nodeId, "/tmp/init-jboss stop", runAsRoot(false).wrapInInitScript(false));
trackAvailabilityOfProcessOnNode(context.utils().userExecutor().submit(new Callable<ExecResponse>() { trackAvailabilityOfProcessOnNode(context.utils().userExecutor().submit(new Callable<ExecResponse>() {
@Override @Override
public ExecResponse call() { public ExecResponse call() {
return client.runScriptOnNode(nodeId, "./jboss start", runAsRoot(false).wrapInInitScript(false)); return client.runScriptOnNode(nodeId, "/tmp/init-jboss start", runAsRoot(false).wrapInInitScript(false));
} }
@Override @Override

View File

@ -70,6 +70,7 @@ public class StubComputeServiceIntegrationTest extends BaseComputeServiceLiveTes
private static final ExecResponse EXEC_GOOD = new ExecResponse("", "", 0); private static final ExecResponse EXEC_GOOD = new ExecResponse("", "", 0);
private static final ExecResponse EXEC_BAD = new ExecResponse("", "", 1); private static final ExecResponse EXEC_BAD = new ExecResponse("", "", 1);
private static final ExecResponse EXEC_RC_GOOD = new ExecResponse("0", "", 0);
public StubComputeServiceIntegrationTest() { public StubComputeServiceIntegrationTest() {
provider = "stub"; provider = "stub";
@ -268,13 +269,15 @@ public class StubComputeServiceIntegrationTest extends BaseComputeServiceLiveTes
expect(client.exec("ln -fs /tmp/init-" + scriptName + " " + scriptName)).andReturn(EXEC_GOOD); expect(client.exec("ln -fs /tmp/init-" + scriptName + " " + scriptName)).andReturn(EXEC_GOOD);
expect(client.getUsername()).andReturn("root").atLeastOnce(); expect(client.getUsername()).andReturn("root").atLeastOnce();
expect(client.getHostAddress()).andReturn("localhost").atLeastOnce(); expect(client.getHostAddress()).andReturn("localhost").atLeastOnce();
expect(client.exec("./" + scriptName + " init")).andReturn(EXEC_GOOD); expect(client.exec("/tmp/init-" + scriptName + " init")).andReturn(EXEC_GOOD);
expect(client.exec("./" + scriptName + " start")).andReturn(EXEC_GOOD); expect(client.exec("/tmp/init-" + scriptName + " start")).andReturn(EXEC_GOOD);
expect(client.exec("./" + scriptName + " status")).andReturn(EXEC_GOOD); expect(client.exec("/tmp/init-" + scriptName + " status")).andReturn(EXEC_GOOD);
// next status says the script is done, since not found. // next status says the script is done, since not found.
expect(client.exec("./" + scriptName + " status")).andReturn(EXEC_BAD); expect(client.exec("/tmp/init-" + scriptName + " status")).andReturn(EXEC_BAD);
expect(client.exec("./" + scriptName + " tail")).andReturn(EXEC_GOOD); expect(client.exec("/tmp/init-" + scriptName + " stdout")).andReturn(EXEC_GOOD);
expect(client.exec("./" + scriptName + " tailerr")).andReturn(EXEC_GOOD); expect(client.exec("/tmp/init-" + scriptName + " stderr")).andReturn(EXEC_GOOD);
expect(client.exec("/tmp/init-" + scriptName + " exitstatus")).andReturn(EXEC_RC_GOOD);
// note we have to reconnect here, as we updated the login user. // note we have to reconnect here, as we updated the login user.
client.disconnect(); client.disconnect();
@ -307,23 +310,23 @@ public class StubComputeServiceIntegrationTest extends BaseComputeServiceLiveTes
expect(clientNew.exec("ln -fs /tmp/init-" + scriptName + " " + scriptName)).andReturn(EXEC_GOOD); expect(clientNew.exec("ln -fs /tmp/init-" + scriptName + " " + scriptName)).andReturn(EXEC_GOOD);
expect(clientNew.getUsername()).andReturn("web").atLeastOnce(); expect(clientNew.getUsername()).andReturn("web").atLeastOnce();
expect(clientNew.getHostAddress()).andReturn("localhost").atLeastOnce(); expect(clientNew.getHostAddress()).andReturn("localhost").atLeastOnce();
expect(clientNew.exec("./" + scriptName + " init")).andReturn(EXEC_GOOD); expect(clientNew.exec("/tmp/init-" + scriptName + " init")).andReturn(EXEC_GOOD);
expect(clientNew.exec("./" + scriptName + " start")).andReturn(EXEC_GOOD); expect(clientNew.exec("/tmp/init-" + scriptName + " start")).andReturn(EXEC_GOOD);
clientNew.disconnect(); clientNew.disconnect();
clientNew.connect(); clientNew.connect();
expect(clientNew.exec("./" + scriptName + " tail\n")).andReturn(EXEC_GOOD); expect(clientNew.exec("/tmp/init-" + scriptName + " stdout\n")).andReturn(EXEC_GOOD);
clientNew.disconnect(); clientNew.disconnect();
clientNew.connect(); clientNew.connect();
expect(clientNew.exec("./" + scriptName + " stop\n")).andReturn(EXEC_GOOD); expect(clientNew.exec("/tmp/init-" + scriptName + " stop\n")).andReturn(EXEC_GOOD);
clientNew.disconnect(); clientNew.disconnect();
clientNew.connect(); clientNew.connect();
expect(clientNew.exec("./" + scriptName + " start\n")).andReturn(EXEC_GOOD); expect(clientNew.exec("/tmp/init-" + scriptName + " start\n")).andReturn(EXEC_GOOD);
clientNew.disconnect(); clientNew.disconnect();
clientNew.connect(); clientNew.connect();
expect(clientNew.exec("./" + scriptName + " tail\n")).andReturn(EXEC_GOOD); expect(clientNew.exec("/tmp/init-" + scriptName + " stdout\n")).andReturn(EXEC_GOOD);
clientNew.disconnect(); clientNew.disconnect();
} catch (IOException e) { } catch (IOException e) {
Throwables.propagate(e); Throwables.propagate(e);
@ -352,13 +355,14 @@ public class StubComputeServiceIntegrationTest extends BaseComputeServiceLiveTes
expect(client.exec("ln -fs /tmp/init-" + scriptName + " " + scriptName)).andReturn(EXEC_GOOD); expect(client.exec("ln -fs /tmp/init-" + scriptName + " " + scriptName)).andReturn(EXEC_GOOD);
expect(client.getUsername()).andReturn("root").atLeastOnce(); expect(client.getUsername()).andReturn("root").atLeastOnce();
expect(client.getHostAddress()).andReturn(nodeId + "").atLeastOnce(); expect(client.getHostAddress()).andReturn(nodeId + "").atLeastOnce();
expect(client.exec("./" + scriptName + " init")).andReturn(EXEC_GOOD); expect(client.exec("/tmp/init-" + scriptName + " init")).andReturn(EXEC_GOOD);
expect(client.exec("./" + scriptName + " start")).andReturn(EXEC_GOOD); expect(client.exec("/tmp/init-" + scriptName + " start")).andReturn(EXEC_GOOD);
expect(client.exec("./" + scriptName + " status")).andReturn(EXEC_GOOD); expect(client.exec("/tmp/init-" + scriptName + " status")).andReturn(EXEC_GOOD);
// next status says the script is done, since not found. // next status says the script is done, since not found.
expect(client.exec("./" + scriptName + " status")).andReturn(EXEC_BAD); expect(client.exec("/tmp/init-" + scriptName + " status")).andReturn(EXEC_BAD);
expect(client.exec("./" + scriptName + " tail")).andReturn(EXEC_GOOD); expect(client.exec("/tmp/init-" + scriptName + " stdout")).andReturn(EXEC_GOOD);
expect(client.exec("./" + scriptName + " tailerr")).andReturn(EXEC_GOOD); expect(client.exec("/tmp/init-" + scriptName + " stderr")).andReturn(EXEC_GOOD);
expect(client.exec("/tmp/init-" + scriptName + " exitstatus")).andReturn(EXEC_RC_GOOD);
} }
private void helloAndJava(SshClient client) { private void helloAndJava(SshClient client) {

View File

@ -41,7 +41,7 @@ import org.jclouds.concurrent.MoreExecutors;
import org.jclouds.concurrent.config.ExecutorServiceModule; import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.domain.LoginCredentials; import org.jclouds.domain.LoginCredentials;
import org.jclouds.predicates.RetryablePredicateTest; import org.jclouds.predicates.RetryablePredicateTest;
import org.jclouds.scriptbuilder.InitBuilder; import org.jclouds.scriptbuilder.InitScript;
import org.jclouds.scriptbuilder.domain.OsFamily; import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshClient;
@ -50,7 +50,7 @@ import org.testng.annotations.Test;
import com.google.common.base.Functions; import com.google.common.base.Functions;
import com.google.common.base.Stopwatch; import com.google.common.base.Stopwatch;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.eventbus.EventBus;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.assistedinject.FactoryModuleBuilder; import com.google.inject.assistedinject.FactoryModuleBuilder;
@ -62,6 +62,8 @@ import com.google.inject.name.Names;
@Test(groups = "unit", singleThreaded = true, testName = "RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest") @Test(groups = "unit", singleThreaded = true, testName = "RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest")
public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest { public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
EventBus eventBus = new EventBus();
BlockUntilInitScriptStatusIsZeroThenReturnOutput.Factory statusFactory = Guice.createInjector( BlockUntilInitScriptStatusIsZeroThenReturnOutput.Factory statusFactory = Guice.createInjector(
new ExecutorServiceModule(MoreExecutors.sameThreadExecutor(), MoreExecutors.sameThreadExecutor()), new ExecutorServiceModule(MoreExecutors.sameThreadExecutor(), MoreExecutors.sameThreadExecutor()),
new AbstractModule() { new AbstractModule() {
@ -98,7 +100,7 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete( RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete(
statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)), statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)),
InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command, eventBus, InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command,
new RunScriptOptions()); new RunScriptOptions());
testMe.call(); testMe.call();
@ -137,13 +139,13 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
*/ */
private void runDefaults(IAnswer<ExecResponse> answerForScriptStatus, int timesForScriptStatus) { private void runDefaults(IAnswer<ExecResponse> answerForScriptStatus, int timesForScriptStatus) {
Statement command = exec("doFoo"); Statement command = exec("doFoo");
NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.RUNNING).credentials( NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.RUNNING)
new LoginCredentials("tester", "testpassword!", null, false)).build(); .credentials(LoginCredentials.builder().user("tester").password("testpassword!").build()).build();
SshClient sshClient = createMock(SshClient.class); SshClient sshClient = createMock(SshClient.class);
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0", InitScript init = InitScript.builder().name("jclouds-script-0").home("/tmp/jclouds-script-0").run(command)
ImmutableMap.<String, String> of(), ImmutableSet.of(command)); .build();
sshClient.connect(); sshClient.connect();
sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX)); sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX));
@ -154,27 +156,28 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0));
expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn( expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn(
new ExecResponse("", "", 0)); new ExecResponse("", "", 0));
expect(sshClient.exec("./jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0));
// start script as root via sudo, note that since there's no adminPassword we do a straight // start script as root via sudo, note that since there's no adminPassword we do a straight
// sudo // sudo
expect(sshClient.exec("sudo ./jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("sudo /tmp/init-jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0));
// signal the command completed // signal the command completed
if (answerForScriptStatus == null) { if (answerForScriptStatus == null) {
expect(sshClient.exec("./jclouds-script-0 status")).andReturn(new ExecResponse("", "", 1)).times(1); expect(sshClient.exec("/tmp/init-jclouds-script-0 status")).andReturn(new ExecResponse("", "", 1)).times(1);
} else { } else {
expect(sshClient.exec("./jclouds-script-0 status")).andAnswer(answerForScriptStatus).times(timesForScriptStatus); expect(sshClient.exec("/tmp/init-jclouds-script-0 status")).andAnswer(answerForScriptStatus).times(timesForScriptStatus);
} }
expect(sshClient.exec("./jclouds-script-0 tail")).andReturn(new ExecResponse("out", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 stdout")).andReturn(new ExecResponse("out", "", 0));
expect(sshClient.exec("./jclouds-script-0 tailerr")).andReturn(new ExecResponse("err", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 stderr")).andReturn(new ExecResponse("err", "", 0));
expect(sshClient.exec("/tmp/init-jclouds-script-0 exitstatus")).andReturn(new ExecResponse("0", "", 0));
sshClient.disconnect(); sshClient.disconnect();
replay(sshClient); replay(sshClient);
RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete( RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete(
statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)), statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)),
InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command, eventBus, InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command,
new RunScriptOptions()); new RunScriptOptions());
assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0"); assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0");
@ -195,8 +198,8 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
SshClient sshClient = createMock(SshClient.class); SshClient sshClient = createMock(SshClient.class);
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0", InitScript init = InitScript.builder().name("jclouds-script-0").home("/tmp/jclouds-script-0").run(command)
ImmutableMap.<String, String> of(), ImmutableSet.of(command)); .build();
sshClient.connect(); sshClient.connect();
sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX)); sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX));
@ -207,22 +210,23 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0));
expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn( expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn(
new ExecResponse("", "", 0)); new ExecResponse("", "", 0));
expect(sshClient.exec("./jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0));
// since there's an adminPassword we must pass this in // since there's an adminPassword we must pass this in
expect(sshClient.exec("echo 'testpassword!'|sudo -S ./jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("echo 'testpassword!'|sudo -S /tmp/init-jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0));
// signal the command completed // signal the command completed
expect(sshClient.exec("./jclouds-script-0 status")).andReturn(new ExecResponse("", "", 1)); expect(sshClient.exec("/tmp/init-jclouds-script-0 status")).andReturn(new ExecResponse("", "", 1));
expect(sshClient.exec("./jclouds-script-0 tail")).andReturn(new ExecResponse("out", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 stdout")).andReturn(new ExecResponse("out", "", 0));
expect(sshClient.exec("./jclouds-script-0 tailerr")).andReturn(new ExecResponse("err", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 stderr")).andReturn(new ExecResponse("err", "", 0));
expect(sshClient.exec("/tmp/init-jclouds-script-0 exitstatus")).andReturn(new ExecResponse("0", "", 0));
sshClient.disconnect(); sshClient.disconnect();
replay(sshClient); replay(sshClient);
RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete( RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete(
statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)), statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)),
InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command, eventBus, InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command,
new RunScriptOptions()); new RunScriptOptions());
assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0"); assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0");
@ -243,8 +247,8 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
SshClient sshClient = createMock(SshClient.class); SshClient sshClient = createMock(SshClient.class);
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0", InitScript init = InitScript.builder().name("jclouds-script-0").home("/tmp/jclouds-script-0").run(command)
ImmutableMap.<String, String> of(), ImmutableSet.of(command)); .build();
sshClient.connect(); sshClient.connect();
sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX)); sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX));
@ -255,22 +259,23 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0));
expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn( expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn(
new ExecResponse("", "", 0)); new ExecResponse("", "", 0));
expect(sshClient.exec("./jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0));
// kick off as current user // kick off as current user
expect(sshClient.exec("./jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0));
// signal the command completed // signal the command completed
expect(sshClient.exec("./jclouds-script-0 status")).andReturn(new ExecResponse("", "", 1)); expect(sshClient.exec("/tmp/init-jclouds-script-0 status")).andReturn(new ExecResponse("", "", 1));
expect(sshClient.exec("./jclouds-script-0 tail")).andReturn(new ExecResponse("out", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 stdout")).andReturn(new ExecResponse("out", "", 0));
expect(sshClient.exec("./jclouds-script-0 tailerr")).andReturn(new ExecResponse("err", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 stderr")).andReturn(new ExecResponse("err", "", 0));
expect(sshClient.exec("/tmp/init-jclouds-script-0 exitstatus")).andReturn(new ExecResponse("0", "", 0));
sshClient.disconnect(); sshClient.disconnect();
replay(sshClient); replay(sshClient);
RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete( RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete(
statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)), statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)),
InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command, eventBus, InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command,
new RunScriptOptions().runAsRoot(false)); new RunScriptOptions().runAsRoot(false));
assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0"); assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0");
@ -284,4 +289,53 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
verify(sshClient); verify(sshClient);
} }
public void testBadReturnCode() {
Statement command = exec("doFoo");
NodeMetadata node = new NodeMetadataBuilder().ids("badreturncode").state(NodeState.RUNNING).credentials(
new LoginCredentials("tester", "testpassword!", null, true)).build();
SshClient sshClient = createMock(SshClient.class);
InitScript init = InitScript.builder().name("jclouds-script-0").home("/tmp/jclouds-script-0").run(command)
.build();
sshClient.connect();
sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX));
expect(sshClient.getUsername()).andReturn("tester").atLeastOnce();
expect(sshClient.getHostAddress()).andReturn("somewhere.example.com").atLeastOnce();
// setup script as default user
expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0));
expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn(
new ExecResponse("", "", 0));
expect(sshClient.exec("/tmp/init-jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0));
// kick off as current user
expect(sshClient.exec("/tmp/init-jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0));
// signal the command completed
expect(sshClient.exec("/tmp/init-jclouds-script-0 status")).andReturn(new ExecResponse("", "", 1));
expect(sshClient.exec("/tmp/init-jclouds-script-0 stdout")).andReturn(new ExecResponse("out", "", 0));
expect(sshClient.exec("/tmp/init-jclouds-script-0 stderr")).andReturn(new ExecResponse("err", "", 0));
expect(sshClient.exec("/tmp/init-jclouds-script-0 exitstatus")).andReturn(new ExecResponse("1", "", 0));
sshClient.disconnect();
replay(sshClient);
RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete(
statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)),
eventBus, InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command,
new RunScriptOptions().runAsRoot(false));
assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0");
assertEquals(testMe.getNode(), node);
assertEquals(testMe.getStatement(), init);
testMe.init();
assertEquals(testMe.call(), new ExecResponse("out", "err", 1));
verify(sshClient);
}
} }

View File

@ -31,7 +31,7 @@ import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.NodeState; import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.options.RunScriptOptions; import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.domain.LoginCredentials; import org.jclouds.domain.LoginCredentials;
import org.jclouds.scriptbuilder.InitBuilder; import org.jclouds.scriptbuilder.InitScript;
import org.jclouds.scriptbuilder.domain.OsFamily; import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshClient;
@ -39,13 +39,14 @@ import org.testng.annotations.Test;
import com.google.common.base.Functions; import com.google.common.base.Functions;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.eventbus.EventBus;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit", singleThreaded = true, testName = "RunScriptOnNodeAsInitScriptUsingSshTest") @Test(groups = "unit", singleThreaded = true, testName = "RunScriptOnNodeAsInitScriptUsingSshTest")
public class RunScriptOnNodeAsInitScriptUsingSshTest { public class RunScriptOnNodeAsInitScriptUsingSshTest {
EventBus eventBus = new EventBus();
@Test(expectedExceptions = IllegalStateException.class) @Test(expectedExceptions = IllegalStateException.class)
public void testWithoutInitThrowsIllegalStateException() { public void testWithoutInitThrowsIllegalStateException() {
@ -58,7 +59,7 @@ public class RunScriptOnNodeAsInitScriptUsingSshTest {
replay(sshClient); replay(sshClient);
RunScriptOnNodeAsInitScriptUsingSsh testMe = new RunScriptOnNodeAsInitScriptUsingSsh(Functions RunScriptOnNodeAsInitScriptUsingSsh testMe = new RunScriptOnNodeAsInitScriptUsingSsh(Functions
.forMap(ImmutableMap.of(node, sshClient)), InitScriptConfigurationForTasks.create() .forMap(ImmutableMap.of(node, sshClient)), eventBus, InitScriptConfigurationForTasks.create()
.appendIncrementingNumberToAnonymousTaskNames(), node, command, new RunScriptOptions()); .appendIncrementingNumberToAnonymousTaskNames(), node, command, new RunScriptOptions());
testMe.call(); testMe.call();
@ -71,8 +72,8 @@ public class RunScriptOnNodeAsInitScriptUsingSshTest {
SshClient sshClient = createMock(SshClient.class); SshClient sshClient = createMock(SshClient.class);
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0", InitScript init = InitScript.builder().name("jclouds-script-0").home("/tmp/jclouds-script-0").run(command)
ImmutableMap.<String, String> of(), ImmutableSet.of(command)); .build();
sshClient.connect(); sshClient.connect();
sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX)); sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX));
@ -82,17 +83,17 @@ public class RunScriptOnNodeAsInitScriptUsingSshTest {
// setup script as default user // setup script as default user
expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0));
expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn(new ExecResponse("", "", 0));
expect(sshClient.exec("./jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0));
// start script as root via sudo, note that since there's no adminPassword we do a straight sudo // start script as root via sudo, note that since there's no adminPassword we do a straight sudo
expect(sshClient.exec("sudo ./jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("sudo /tmp/init-jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0));
sshClient.disconnect(); sshClient.disconnect();
replay(sshClient); replay(sshClient);
RunScriptOnNodeAsInitScriptUsingSsh testMe = new RunScriptOnNodeAsInitScriptUsingSsh(Functions RunScriptOnNodeAsInitScriptUsingSsh testMe = new RunScriptOnNodeAsInitScriptUsingSsh(Functions
.forMap(ImmutableMap.of(node, sshClient)), InitScriptConfigurationForTasks.create() .forMap(ImmutableMap.of(node, sshClient)), eventBus, InitScriptConfigurationForTasks.create()
.appendIncrementingNumberToAnonymousTaskNames(), node, command, new RunScriptOptions()); .appendIncrementingNumberToAnonymousTaskNames(), node, command, new RunScriptOptions());
assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0"); assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0");
@ -112,8 +113,8 @@ public class RunScriptOnNodeAsInitScriptUsingSshTest {
SshClient sshClient = createMock(SshClient.class); SshClient sshClient = createMock(SshClient.class);
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0", InitScript init = InitScript.builder().name("jclouds-script-0").home("/tmp/jclouds-script-0").run(command)
ImmutableMap.<String, String> of(), ImmutableSet.of(command)); .build();
sshClient.connect(); sshClient.connect();
sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX)); sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX));
@ -123,17 +124,17 @@ public class RunScriptOnNodeAsInitScriptUsingSshTest {
// setup script as default user // setup script as default user
expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0));
expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn(new ExecResponse("", "", 0));
expect(sshClient.exec("./jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0));
// since there's an adminPassword we must pass this in // since there's an adminPassword we must pass this in
expect(sshClient.exec("echo 'notalot'|sudo -S ./jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("echo 'notalot'|sudo -S /tmp/init-jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0));
sshClient.disconnect(); sshClient.disconnect();
replay(sshClient); replay(sshClient);
RunScriptOnNodeAsInitScriptUsingSsh testMe = new RunScriptOnNodeAsInitScriptUsingSsh(Functions RunScriptOnNodeAsInitScriptUsingSsh testMe = new RunScriptOnNodeAsInitScriptUsingSsh(Functions
.forMap(ImmutableMap.of(node, sshClient)), InitScriptConfigurationForTasks.create() .forMap(ImmutableMap.of(node, sshClient)), eventBus, InitScriptConfigurationForTasks.create()
.appendIncrementingNumberToAnonymousTaskNames(), node, command, new RunScriptOptions()); .appendIncrementingNumberToAnonymousTaskNames(), node, command, new RunScriptOptions());
assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0"); assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0");
@ -154,8 +155,8 @@ public class RunScriptOnNodeAsInitScriptUsingSshTest {
SshClient sshClient = createMock(SshClient.class); SshClient sshClient = createMock(SshClient.class);
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0", InitScript init = InitScript.builder().name("jclouds-script-0").home("/tmp/jclouds-script-0").run(command)
ImmutableMap.<String, String> of(), ImmutableSet.of(command)); .build();
sshClient.connect(); sshClient.connect();
sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX)); sshClient.put("/tmp/init-jclouds-script-0", init.render(OsFamily.UNIX));
@ -165,16 +166,16 @@ public class RunScriptOnNodeAsInitScriptUsingSshTest {
// setup script as default user // setup script as default user
expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("chmod 755 /tmp/init-jclouds-script-0")).andReturn(new ExecResponse("", "", 0));
expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("ln -fs /tmp/init-jclouds-script-0 jclouds-script-0")).andReturn(new ExecResponse("", "", 0));
expect(sshClient.exec("./jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0));
// kick off as current user // kick off as current user
expect(sshClient.exec("./jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0)); expect(sshClient.exec("/tmp/init-jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0));
sshClient.disconnect(); sshClient.disconnect();
replay(sshClient); replay(sshClient);
RunScriptOnNodeAsInitScriptUsingSsh testMe = new RunScriptOnNodeAsInitScriptUsingSsh(Functions RunScriptOnNodeAsInitScriptUsingSsh testMe = new RunScriptOnNodeAsInitScriptUsingSsh(Functions
.forMap(ImmutableMap.of(node, sshClient)), InitScriptConfigurationForTasks.create() .forMap(ImmutableMap.of(node, sshClient)), eventBus, InitScriptConfigurationForTasks.create()
.appendIncrementingNumberToAnonymousTaskNames(), node, command, new RunScriptOptions().runAsRoot(false)); .appendIncrementingNumberToAnonymousTaskNames(), node, command, new RunScriptOptions().runAsRoot(false));
assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0"); assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0");

View File

@ -34,12 +34,15 @@ import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.eventbus.EventBus;
/** /**
* @author Adam Lowe * @author Adam Lowe
*/ */
@Test(groups = { "unit" }, singleThreaded = true) @Test(groups = { "unit" }, singleThreaded = true)
public class RunScriptOnNodeUsingSshTest { public class RunScriptOnNodeUsingSshTest {
EventBus eventBus = new EventBus();
private SshClient sshClient; private SshClient sshClient;
private NodeMetadata node; private NodeMetadata node;
private Function<NodeMetadata, SshClient> sshFactory; private Function<NodeMetadata, SshClient> sshFactory;
@ -59,7 +62,7 @@ public class RunScriptOnNodeUsingSshTest {
} }
public void simpleTest() { public void simpleTest() {
RunScriptOnNodeUsingSsh testMe = new RunScriptOnNodeUsingSsh(sshFactory, node, exec("echo $USER\necho $USER"), RunScriptOnNodeUsingSsh testMe = new RunScriptOnNodeUsingSsh(sshFactory, eventBus, node, exec("echo $USER\necho $USER"),
wrapInInitScript(false).runAsRoot(false)); wrapInInitScript(false).runAsRoot(false));
testMe.init(); testMe.init();
@ -75,7 +78,7 @@ public class RunScriptOnNodeUsingSshTest {
} }
public void simpleRootTest() { public void simpleRootTest() {
RunScriptOnNodeUsingSsh testMe = new RunScriptOnNodeUsingSsh(sshFactory, node, exec("echo $USER\necho $USER"), RunScriptOnNodeUsingSsh testMe = new RunScriptOnNodeUsingSsh(sshFactory, eventBus, node, exec("echo $USER\necho $USER"),
wrapInInitScript(false).runAsRoot(true)); wrapInInitScript(false).runAsRoot(true));
testMe.init(); testMe.init();
@ -97,7 +100,7 @@ public class RunScriptOnNodeUsingSshTest {
expect(node.getCredentials()).andReturn(new LoginCredentials("tester", "testpassword!", null, true)) expect(node.getCredentials()).andReturn(new LoginCredentials("tester", "testpassword!", null, true))
.atLeastOnce(); .atLeastOnce();
replay(node); replay(node);
RunScriptOnNodeUsingSsh testMe = new RunScriptOnNodeUsingSsh(sshFactory, node, exec("echo $USER\necho $USER"), RunScriptOnNodeUsingSsh testMe = new RunScriptOnNodeUsingSsh(sshFactory, eventBus, node, exec("echo $USER\necho $USER"),
wrapInInitScript(false).runAsRoot(true)); wrapInInitScript(false).runAsRoot(true));
testMe.init(); testMe.init();
@ -114,7 +117,7 @@ public class RunScriptOnNodeUsingSshTest {
} }
public void testUserAddAsRoot() { public void testUserAddAsRoot() {
RunScriptOnNodeUsingSsh testMe = new RunScriptOnNodeUsingSsh(sshFactory, node, UserAdd.builder() RunScriptOnNodeUsingSsh testMe = new RunScriptOnNodeUsingSsh(sshFactory, eventBus, node, UserAdd.builder()
.login("testuser").build(), wrapInInitScript(false).runAsRoot(true).overrideLoginPassword("test")); .login("testuser").build(), wrapInInitScript(false).runAsRoot(true).overrideLoginPassword("test"));
testMe.init(); testMe.init();

View File

@ -10,11 +10,11 @@ function abort {
function default { function default {
export INSTANCE_NAME="bootstrap" export INSTANCE_NAME="bootstrap"
export INSTANCE_HOME="/tmp/bootstrap" export INSTANCE_HOME="/tmp/bootstrap"
export LOG_DIR="/tmp/bootstrap" export LOG_DIR="$INSTANCE_HOME"
return 0 return $?
} }
function bootstrap { function bootstrap {
return 0 return $?
} }
function findPid { function findPid {
unset FOUND_PID; unset FOUND_PID;
@ -62,35 +62,41 @@ init)
mkdir -p $INSTANCE_HOME mkdir -p $INSTANCE_HOME
# create runscript header # create runscript header
cat > $INSTANCE_HOME/bootstrap.sh <<END_OF_SCRIPT cat > $INSTANCE_HOME/bootstrap.sh <<-'END_OF_JCLOUDS_SCRIPT'
#!/bin/bash #!/bin/bash
set +u set +u
shopt -s xpg_echo shopt -s xpg_echo
shopt -s expand_aliases shopt -s expand_aliases
PROMPT_COMMAND='echo -ne "\033]0;bootstrap\007"'
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin PROMPT_COMMAND='echo -ne \"\033]0;bootstrap\007\"'
export INSTANCE_NAME='bootstrap' export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME' export INSTANCE_NAME='bootstrap'
export LOG_DIR='$LOG_DIR' END_OF_JCLOUDS_SCRIPT
function abort { cat >> $INSTANCE_HOME/bootstrap.sh <<-END_OF_JCLOUDS_SCRIPT
echo "aborting: \$@" 1>&2 export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME'
export LOG_DIR='$LOG_DIR'
END_OF_JCLOUDS_SCRIPT
cat >> $INSTANCE_HOME/bootstrap.sh <<-'END_OF_JCLOUDS_SCRIPT'
function abort {
echo "aborting: $@" 1>&2
exit 1 exit 1
} }
alias apt-get-install="apt-get install -f -y -qq --force-yes" alias apt-get-install="apt-get install -f -y -qq --force-yes"
alias apt-get-upgrade="(apt-get update -qq&&apt-get upgrade -y -qq)" alias apt-get-upgrade="(apt-get update -qq&&apt-get upgrade -y -qq)"
function ensure_cmd_or_install_package_apt(){ function ensure_cmd_or_install_package_apt(){
local cmd=\$1 local cmd=$1
local pkg=\$2 local pkg=$2
hash \$cmd 2>/dev/null || apt-get-install \$pkg || ( apt-get-upgrade && apt-get-install \$pkg ) hash $cmd 2>/dev/null || apt-get-install $pkg || ( apt-get-upgrade && apt-get-install $pkg )
} }
function ensure_cmd_or_install_package_yum(){ function ensure_cmd_or_install_package_yum(){
local cmd=\$1 local cmd=$1
local pkg=\$2 local pkg=$2
hash \$cmd 2>/dev/null || yum --nogpgcheck -y ensure \$pkg hash $cmd 2>/dev/null || yum --nogpgcheck -y ensure $pkg
} }
function ensure_netutils_apt() { function ensure_netutils_apt() {
@ -106,7 +112,7 @@ function ensure_netutils_yum() {
# most network services require that the hostname is in # most network services require that the hostname is in
# the /etc/hosts file, or they won't operate # the /etc/hosts file, or they won't operate
function ensure_hostname_in_hosts() { function ensure_hostname_in_hosts() {
egrep -q `hostname` /etc/hosts || awk -v hostname=`hostname` 'END { print \$1" "hostname }' /proc/net/arp >> /etc/hosts egrep -q `hostname` /etc/hosts || awk -v hostname=`hostname` 'END { print $1" "hostname }' /proc/net/arp >> /etc/hosts
} }
# download locations for many services are at public dns # download locations for many services are at public dns
@ -127,60 +133,63 @@ function setupPublicCurl() {
ensure_can_resolve_public_dns ensure_can_resolve_public_dns
return 0 return 0
} }
END_OF_SCRIPT
END_OF_JCLOUDS_SCRIPT
# add desired commands from the user # add desired commands from the user
cat >> $INSTANCE_HOME/bootstrap.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/bootstrap.sh <<-'END_OF_JCLOUDS_SCRIPT'
cd $INSTANCE_HOME cd $INSTANCE_HOME
rm /etc/sudoers rm -f $INSTANCE_HOME/rc
cat >> /etc/sudoers <<'END_OF_FILE' trap 'echo $?>$INSTANCE_HOME/rc' 0 1 2 3 15
root ALL = (ALL) ALL cat > /etc/sudoers <<-'END_OF_JCLOUDS_FILE'
%wheel ALL = (ALL) NOPASSWD:ALL root ALL = (ALL) ALL
END_OF_FILE %wheel ALL = (ALL) NOPASSWD:ALL
chmod 0440 /etc/sudoers END_OF_JCLOUDS_FILE
mkdir -p /home/users chmod 0440 /etc/sudoers
groupadd -f wheel mkdir -p /home/users
useradd -s /bin/bash -g wheel -m -d /home/users/defaultAdminUsername -p 'crypt(randompassword)' defaultAdminUsername groupadd -f wheel
mkdir -p /home/users/defaultAdminUsername/.ssh useradd -s /bin/bash -g wheel -m -d /home/users/defaultAdminUsername -p 'crypt(randompassword)' defaultAdminUsername
cat >> /home/users/defaultAdminUsername/.ssh/authorized_keys <<'END_OF_FILE' mkdir -p /home/users/defaultAdminUsername/.ssh
publicKey cat >> /home/users/defaultAdminUsername/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'
END_OF_FILE publicKey
chmod 600 /home/users/defaultAdminUsername/.ssh/authorized_keys END_OF_JCLOUDS_FILE
chown -R defaultAdminUsername /home/users/defaultAdminUsername chmod 600 /home/users/defaultAdminUsername/.ssh/authorized_keys
exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no chown -R defaultAdminUsername /home/users/defaultAdminUsername
PermitRootLogin no exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3 PermitRootLogin no
/etc/init.d/sshd reload||/etc/init.d/ssh reload " 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3
awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(randompassword)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}} hash service 2>/dev/null && service ssh reload || /etc/init.d/ssh* reload
test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(randompassword)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}}
setupPublicCurl || return 1 test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow
curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.oracle.com/otn-pub/java/jdk/7/jdk-7-linux-x64.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -) setupPublicCurl || return 1
mv /usr/local/jdk* /usr/local/jdk/ curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.oracle.com/otn-pub/java/jdk/7/jdk-7-linux-x64.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -)
test -n "$SUDO_USER" && mv /usr/local/jdk* /usr/local/jdk/
cat >> /home/$SUDO_USER/.bashrc <<'END_OF_FILE' test -n "$SUDO_USER" &&
export JAVA_HOME=/usr/local/jdk cat >> /home/$SUDO_USER/.bashrc <<-'END_OF_JCLOUDS_FILE'
export PATH=$JAVA_HOME/bin:$PATH export JAVA_HOME=/usr/local/jdk
END_OF_FILE export PATH=$JAVA_HOME/bin:$PATH
cat >> /etc/bashrc <<'END_OF_FILE' END_OF_JCLOUDS_FILE
export JAVA_HOME=/usr/local/jdk cat >> /etc/bashrc <<-'END_OF_JCLOUDS_FILE'
export PATH=$JAVA_HOME/bin:$PATH export JAVA_HOME=/usr/local/jdk
END_OF_FILE export PATH=$JAVA_HOME/bin:$PATH
cat >> $HOME/.bashrc <<'END_OF_FILE' END_OF_JCLOUDS_FILE
export JAVA_HOME=/usr/local/jdk cat >> $HOME/.bashrc <<-'END_OF_JCLOUDS_FILE'
export PATH=$JAVA_HOME/bin:$PATH export JAVA_HOME=/usr/local/jdk
END_OF_FILE export PATH=$JAVA_HOME/bin:$PATH
cat >> /etc/skel/.bashrc <<'END_OF_FILE' END_OF_JCLOUDS_FILE
export JAVA_HOME=/usr/local/jdk cat >> /etc/skel/.bashrc <<-'END_OF_JCLOUDS_FILE'
export PATH=$JAVA_HOME/bin:$PATH export JAVA_HOME=/usr/local/jdk
END_OF_FILE export PATH=$JAVA_HOME/bin:$PATH
ln -fs /usr/local/jdk/bin/java /usr/bin/java END_OF_JCLOUDS_FILE
ln -fs /usr/local/jdk/bin/java /usr/bin/java
END_OF_SCRIPT END_OF_JCLOUDS_SCRIPT
# add runscript footer # add runscript footer
cat >> $INSTANCE_HOME/bootstrap.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/bootstrap.sh <<-'END_OF_JCLOUDS_SCRIPT'
exit 0 exit $?
END_OF_SCRIPT
END_OF_JCLOUDS_SCRIPT
chmod u+x $INSTANCE_HOME/bootstrap.sh chmod u+x $INSTANCE_HOME/bootstrap.sh
;; ;;
@ -201,6 +210,17 @@ start)
default || exit 1 default || exit 1
forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1 forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1
;; ;;
stdout)
default || exit 1
cat $LOG_DIR/stdout.log
;;
stderr)
default || exit 1
cat $LOG_DIR/stderr.log
;;
exitstatus)
default || exit 1
[ -f $LOG_DIR/rc ] && cat $LOG_DIR/rc;;
tail) tail)
default || exit 1 default || exit 1
tail $LOG_DIR/stdout.log tail $LOG_DIR/stdout.log
@ -214,4 +234,4 @@ run)
$INSTANCE_HOME/$INSTANCE_NAME.sh $INSTANCE_HOME/$INSTANCE_NAME.sh
;; ;;
esac esac
exit 0 exit $?

View File

@ -10,11 +10,11 @@ function abort {
function default { function default {
export INSTANCE_NAME="configure-jboss" export INSTANCE_NAME="configure-jboss"
export INSTANCE_HOME="/tmp/configure-jboss" export INSTANCE_HOME="/tmp/configure-jboss"
export LOG_DIR="/tmp/configure-jboss" export LOG_DIR="$INSTANCE_HOME"
return 0 return $?
} }
function configure-jboss { function configure-jboss {
return 0 return $?
} }
function findPid { function findPid {
unset FOUND_PID; unset FOUND_PID;
@ -62,35 +62,41 @@ init)
mkdir -p $INSTANCE_HOME mkdir -p $INSTANCE_HOME
# create runscript header # create runscript header
cat > $INSTANCE_HOME/configure-jboss.sh <<END_OF_SCRIPT cat > $INSTANCE_HOME/configure-jboss.sh <<-'END_OF_JCLOUDS_SCRIPT'
#!/bin/bash #!/bin/bash
set +u set +u
shopt -s xpg_echo shopt -s xpg_echo
shopt -s expand_aliases shopt -s expand_aliases
PROMPT_COMMAND='echo -ne "\033]0;configure-jboss\007"'
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin PROMPT_COMMAND='echo -ne \"\033]0;configure-jboss\007\"'
export INSTANCE_NAME='configure-jboss' export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME' export INSTANCE_NAME='configure-jboss'
export LOG_DIR='$LOG_DIR' END_OF_JCLOUDS_SCRIPT
function abort { cat >> $INSTANCE_HOME/configure-jboss.sh <<-END_OF_JCLOUDS_SCRIPT
echo "aborting: \$@" 1>&2 export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME'
export LOG_DIR='$LOG_DIR'
END_OF_JCLOUDS_SCRIPT
cat >> $INSTANCE_HOME/configure-jboss.sh <<-'END_OF_JCLOUDS_SCRIPT'
function abort {
echo "aborting: $@" 1>&2
exit 1 exit 1
} }
alias apt-get-install="apt-get install -f -y -qq --force-yes" alias apt-get-install="apt-get install -f -y -qq --force-yes"
alias apt-get-upgrade="(apt-get update -qq&&apt-get upgrade -y -qq)" alias apt-get-upgrade="(apt-get update -qq&&apt-get upgrade -y -qq)"
function ensure_cmd_or_install_package_apt(){ function ensure_cmd_or_install_package_apt(){
local cmd=\$1 local cmd=$1
local pkg=\$2 local pkg=$2
hash \$cmd 2>/dev/null || apt-get-install \$pkg || ( apt-get-upgrade && apt-get-install \$pkg ) hash $cmd 2>/dev/null || apt-get-install $pkg || ( apt-get-upgrade && apt-get-install $pkg )
} }
function ensure_cmd_or_install_package_yum(){ function ensure_cmd_or_install_package_yum(){
local cmd=\$1 local cmd=$1
local pkg=\$2 local pkg=$2
hash \$cmd 2>/dev/null || yum --nogpgcheck -y ensure \$pkg hash $cmd 2>/dev/null || yum --nogpgcheck -y ensure $pkg
} }
function ensure_netutils_apt() { function ensure_netutils_apt() {
@ -106,7 +112,7 @@ function ensure_netutils_yum() {
# most network services require that the hostname is in # most network services require that the hostname is in
# the /etc/hosts file, or they won't operate # the /etc/hosts file, or they won't operate
function ensure_hostname_in_hosts() { function ensure_hostname_in_hosts() {
egrep -q `hostname` /etc/hosts || awk -v hostname=`hostname` 'END { print \$1" "hostname }' /proc/net/arp >> /etc/hosts egrep -q `hostname` /etc/hosts || awk -v hostname=`hostname` 'END { print $1" "hostname }' /proc/net/arp >> /etc/hosts
} }
# download locations for many services are at public dns # download locations for many services are at public dns
@ -127,69 +133,72 @@ function setupPublicCurl() {
ensure_can_resolve_public_dns ensure_can_resolve_public_dns
return 0 return 0
} }
END_OF_SCRIPT
END_OF_JCLOUDS_SCRIPT
# add desired commands from the user # add desired commands from the user
cat >> $INSTANCE_HOME/configure-jboss.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/configure-jboss.sh <<-'END_OF_JCLOUDS_SCRIPT'
cd $INSTANCE_HOME cd $INSTANCE_HOME
rm /etc/sudoers rm -f $INSTANCE_HOME/rc
cat >> /etc/sudoers <<'END_OF_FILE' trap 'echo $?>$INSTANCE_HOME/rc' 0 1 2 3 15
root ALL = (ALL) ALL cat > /etc/sudoers <<-'END_OF_JCLOUDS_FILE'
%wheel ALL = (ALL) NOPASSWD:ALL root ALL = (ALL) ALL
END_OF_FILE %wheel ALL = (ALL) NOPASSWD:ALL
chmod 0440 /etc/sudoers END_OF_JCLOUDS_FILE
mkdir -p /home/users chmod 0440 /etc/sudoers
groupadd -f wheel mkdir -p /home/users
useradd -s /bin/bash -g wheel -m -d /home/users/web -p 'crypt(randompassword)' web groupadd -f wheel
mkdir -p /home/users/web/.ssh useradd -s /bin/bash -g wheel -m -d /home/users/web -p 'crypt(randompassword)' web
cat >> /home/users/web/.ssh/authorized_keys <<'END_OF_FILE' mkdir -p /home/users/web/.ssh
publicKey cat >> /home/users/web/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'
END_OF_FILE publicKey
chmod 600 /home/users/web/.ssh/authorized_keys END_OF_JCLOUDS_FILE
chown -R web /home/users/web chmod 600 /home/users/web/.ssh/authorized_keys
exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no chown -R web /home/users/web
PermitRootLogin no exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3 PermitRootLogin no
/etc/init.d/sshd reload||/etc/init.d/ssh reload " 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3
awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(randompassword)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}} hash service 2>/dev/null && service ssh reload || /etc/init.d/ssh* reload
test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(randompassword)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}}
setupPublicCurl || return 1 test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow
curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.oracle.com/otn-pub/java/jdk/7/jdk-7-linux-x64.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -) setupPublicCurl || return 1
mv /usr/local/jdk* /usr/local/jdk/ curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.oracle.com/otn-pub/java/jdk/7/jdk-7-linux-x64.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -)
test -n "$SUDO_USER" && mv /usr/local/jdk* /usr/local/jdk/
cat >> /home/$SUDO_USER/.bashrc <<'END_OF_FILE' test -n "$SUDO_USER" &&
export JAVA_HOME=/usr/local/jdk cat >> /home/$SUDO_USER/.bashrc <<-'END_OF_JCLOUDS_FILE'
export PATH=$JAVA_HOME/bin:$PATH export JAVA_HOME=/usr/local/jdk
END_OF_FILE export PATH=$JAVA_HOME/bin:$PATH
cat >> /etc/bashrc <<'END_OF_FILE' END_OF_JCLOUDS_FILE
export JAVA_HOME=/usr/local/jdk cat >> /etc/bashrc <<-'END_OF_JCLOUDS_FILE'
export PATH=$JAVA_HOME/bin:$PATH export JAVA_HOME=/usr/local/jdk
END_OF_FILE export PATH=$JAVA_HOME/bin:$PATH
cat >> $HOME/.bashrc <<'END_OF_FILE' END_OF_JCLOUDS_FILE
export JAVA_HOME=/usr/local/jdk cat >> $HOME/.bashrc <<-'END_OF_JCLOUDS_FILE'
export PATH=$JAVA_HOME/bin:$PATH export JAVA_HOME=/usr/local/jdk
END_OF_FILE export PATH=$JAVA_HOME/bin:$PATH
cat >> /etc/skel/.bashrc <<'END_OF_FILE' END_OF_JCLOUDS_FILE
export JAVA_HOME=/usr/local/jdk cat >> /etc/skel/.bashrc <<-'END_OF_JCLOUDS_FILE'
export PATH=$JAVA_HOME/bin:$PATH export JAVA_HOME=/usr/local/jdk
END_OF_FILE export PATH=$JAVA_HOME/bin:$PATH
ln -fs /usr/local/jdk/bin/java /usr/bin/java END_OF_JCLOUDS_FILE
iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT ln -fs /usr/local/jdk/bin/java /usr/bin/java
iptables -I INPUT 1 -p tcp --dport 8080 -j ACCEPT iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT
iptables-save iptables -I INPUT 1 -p tcp --dport 8080 -j ACCEPT
curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.jboss.org/jbossas/7.0/jboss-as-7.0.2.Final/jboss-as-web-7.0.2.Final.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -) iptables-save
mkdir -p /usr/local/jboss curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.jboss.org/jbossas/7.0/jboss-as-7.0.2.Final/jboss-as-web-7.0.2.Final.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -)
mv /usr/local/jboss-*/* /usr/local/jboss mkdir -p /usr/local/jboss
(cd /usr/local/jboss/standalone/configuration && sed 's~inet-address value=.*/~any-address/~g' standalone.xml > standalone.xml.new && mv standalone.xml.new standalone.xml) mv /usr/local/jboss-*/* /usr/local/jboss
chmod -R oug+r+w /usr/local/jboss (cd /usr/local/jboss/standalone/configuration && sed 's~inet-address value=.*/~any-address/~g' standalone.xml > standalone.xml.new && mv standalone.xml.new standalone.xml)
chown -R web /usr/local/jboss chmod -R oug+r+w /usr/local/jboss
chown -R web /usr/local/jboss
END_OF_SCRIPT END_OF_JCLOUDS_SCRIPT
# add runscript footer # add runscript footer
cat >> $INSTANCE_HOME/configure-jboss.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/configure-jboss.sh <<-'END_OF_JCLOUDS_SCRIPT'
exit 0 exit $?
END_OF_SCRIPT
END_OF_JCLOUDS_SCRIPT
chmod u+x $INSTANCE_HOME/configure-jboss.sh chmod u+x $INSTANCE_HOME/configure-jboss.sh
;; ;;
@ -210,6 +219,17 @@ start)
default || exit 1 default || exit 1
forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1 forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1
;; ;;
stdout)
default || exit 1
cat $LOG_DIR/stdout.log
;;
stderr)
default || exit 1
cat $LOG_DIR/stderr.log
;;
exitstatus)
default || exit 1
[ -f $LOG_DIR/rc ] && cat $LOG_DIR/rc;;
tail) tail)
default || exit 1 default || exit 1
tail $LOG_DIR/stdout.log tail $LOG_DIR/stdout.log
@ -223,4 +243,4 @@ run)
$INSTANCE_HOME/$INSTANCE_NAME.sh $INSTANCE_HOME/$INSTANCE_NAME.sh
;; ;;
esac esac
exit 0 exit $?

View File

@ -10,11 +10,11 @@ function abort {
function default { function default {
export INSTANCE_NAME="runScriptWithCreds" export INSTANCE_NAME="runScriptWithCreds"
export INSTANCE_HOME="/tmp/runScriptWithCreds" export INSTANCE_HOME="/tmp/runScriptWithCreds"
export LOG_DIR="/tmp/runScriptWithCreds" export LOG_DIR="$INSTANCE_HOME"
return 0 return $?
} }
function runScriptWithCreds { function runScriptWithCreds {
return 0 return $?
} }
function findPid { function findPid {
unset FOUND_PID; unset FOUND_PID;
@ -62,35 +62,41 @@ init)
mkdir -p $INSTANCE_HOME mkdir -p $INSTANCE_HOME
# create runscript header # create runscript header
cat > $INSTANCE_HOME/runScriptWithCreds.sh <<END_OF_SCRIPT cat > $INSTANCE_HOME/runScriptWithCreds.sh <<-'END_OF_JCLOUDS_SCRIPT'
#!/bin/bash #!/bin/bash
set +u set +u
shopt -s xpg_echo shopt -s xpg_echo
shopt -s expand_aliases shopt -s expand_aliases
PROMPT_COMMAND='echo -ne "\033]0;runScriptWithCreds\007"'
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin PROMPT_COMMAND='echo -ne \"\033]0;runScriptWithCreds\007\"'
export INSTANCE_NAME='runScriptWithCreds' export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME' export INSTANCE_NAME='runScriptWithCreds'
export LOG_DIR='$LOG_DIR' END_OF_JCLOUDS_SCRIPT
function abort { cat >> $INSTANCE_HOME/runScriptWithCreds.sh <<-END_OF_JCLOUDS_SCRIPT
echo "aborting: \$@" 1>&2 export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME'
export LOG_DIR='$LOG_DIR'
END_OF_JCLOUDS_SCRIPT
cat >> $INSTANCE_HOME/runScriptWithCreds.sh <<-'END_OF_JCLOUDS_SCRIPT'
function abort {
echo "aborting: $@" 1>&2
exit 1 exit 1
} }
alias apt-get-install="apt-get install -f -y -qq --force-yes" alias apt-get-install="apt-get install -f -y -qq --force-yes"
alias apt-get-upgrade="(apt-get update -qq&&apt-get upgrade -y -qq)" alias apt-get-upgrade="(apt-get update -qq&&apt-get upgrade -y -qq)"
function ensure_cmd_or_install_package_apt(){ function ensure_cmd_or_install_package_apt(){
local cmd=\$1 local cmd=$1
local pkg=\$2 local pkg=$2
hash \$cmd 2>/dev/null || apt-get-install \$pkg || ( apt-get-upgrade && apt-get-install \$pkg ) hash $cmd 2>/dev/null || apt-get-install $pkg || ( apt-get-upgrade && apt-get-install $pkg )
} }
function ensure_cmd_or_install_package_yum(){ function ensure_cmd_or_install_package_yum(){
local cmd=\$1 local cmd=$1
local pkg=\$2 local pkg=$2
hash \$cmd 2>/dev/null || yum --nogpgcheck -y ensure \$pkg hash $cmd 2>/dev/null || yum --nogpgcheck -y ensure $pkg
} }
function ensure_netutils_apt() { function ensure_netutils_apt() {
@ -106,7 +112,7 @@ function ensure_netutils_yum() {
# most network services require that the hostname is in # most network services require that the hostname is in
# the /etc/hosts file, or they won't operate # the /etc/hosts file, or they won't operate
function ensure_hostname_in_hosts() { function ensure_hostname_in_hosts() {
egrep -q `hostname` /etc/hosts || awk -v hostname=`hostname` 'END { print \$1" "hostname }' /proc/net/arp >> /etc/hosts egrep -q `hostname` /etc/hosts || awk -v hostname=`hostname` 'END { print $1" "hostname }' /proc/net/arp >> /etc/hosts
} }
# download locations for many services are at public dns # download locations for many services are at public dns
@ -127,39 +133,43 @@ function setupPublicCurl() {
ensure_can_resolve_public_dns ensure_can_resolve_public_dns
return 0 return 0
} }
END_OF_SCRIPT
END_OF_JCLOUDS_SCRIPT
# add desired commands from the user # add desired commands from the user
cat >> $INSTANCE_HOME/runScriptWithCreds.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/runScriptWithCreds.sh <<-'END_OF_JCLOUDS_SCRIPT'
cd $INSTANCE_HOME cd $INSTANCE_HOME
setupPublicCurl || exit 1 rm -f $INSTANCE_HOME/rc
curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.oracle.com/otn-pub/java/jdk/7/jdk-7-linux-x64.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -) trap 'echo $?>$INSTANCE_HOME/rc' 0 1 2 3 15
mv /usr/local/jdk* /usr/local/jdk/ setupPublicCurl || exit 1
test -n "$SUDO_USER" && curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.oracle.com/otn-pub/java/jdk/7/jdk-7-linux-x64.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -)
cat >> /home/$SUDO_USER/.bashrc <<'END_OF_FILE' mv /usr/local/jdk* /usr/local/jdk/
export JAVA_HOME=/usr/local/jdk test -n "$SUDO_USER" &&
export PATH=$JAVA_HOME/bin:$PATH cat >> /home/$SUDO_USER/.bashrc <<-'END_OF_JCLOUDS_FILE'
END_OF_FILE export JAVA_HOME=/usr/local/jdk
cat >> /etc/bashrc <<'END_OF_FILE' export PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME=/usr/local/jdk END_OF_JCLOUDS_FILE
export PATH=$JAVA_HOME/bin:$PATH cat >> /etc/bashrc <<-'END_OF_JCLOUDS_FILE'
END_OF_FILE export JAVA_HOME=/usr/local/jdk
cat >> $HOME/.bashrc <<'END_OF_FILE' export PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME=/usr/local/jdk END_OF_JCLOUDS_FILE
export PATH=$JAVA_HOME/bin:$PATH cat >> $HOME/.bashrc <<-'END_OF_JCLOUDS_FILE'
END_OF_FILE export JAVA_HOME=/usr/local/jdk
cat >> /etc/skel/.bashrc <<'END_OF_FILE' export PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME=/usr/local/jdk END_OF_JCLOUDS_FILE
export PATH=$JAVA_HOME/bin:$PATH cat >> /etc/skel/.bashrc <<-'END_OF_JCLOUDS_FILE'
END_OF_FILE export JAVA_HOME=/usr/local/jdk
ln -fs /usr/local/jdk/bin/java /usr/bin/java export PATH=$JAVA_HOME/bin:$PATH
END_OF_JCLOUDS_FILE
ln -fs /usr/local/jdk/bin/java /usr/bin/java
END_OF_SCRIPT END_OF_JCLOUDS_SCRIPT
# add runscript footer # add runscript footer
cat >> $INSTANCE_HOME/runScriptWithCreds.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/runScriptWithCreds.sh <<-'END_OF_JCLOUDS_SCRIPT'
exit 0 exit $?
END_OF_SCRIPT
END_OF_JCLOUDS_SCRIPT
chmod u+x $INSTANCE_HOME/runScriptWithCreds.sh chmod u+x $INSTANCE_HOME/runScriptWithCreds.sh
;; ;;
@ -180,6 +190,17 @@ start)
default || exit 1 default || exit 1
forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1 forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1
;; ;;
stdout)
default || exit 1
cat $LOG_DIR/stdout.log
;;
stderr)
default || exit 1
cat $LOG_DIR/stderr.log
;;
exitstatus)
default || exit 1
[ -f $LOG_DIR/rc ] && cat $LOG_DIR/rc;;
tail) tail)
default || exit 1 default || exit 1
tail $LOG_DIR/stdout.log tail $LOG_DIR/stdout.log
@ -193,4 +214,4 @@ run)
$INSTANCE_HOME/$INSTANCE_NAME.sh $INSTANCE_HOME/$INSTANCE_NAME.sh
;; ;;
esac esac
exit 0 exit $?

View File

@ -10,11 +10,11 @@ function abort {
function default { function default {
export INSTANCE_NAME="adminUpdate" export INSTANCE_NAME="adminUpdate"
export INSTANCE_HOME="/tmp/adminUpdate" export INSTANCE_HOME="/tmp/adminUpdate"
export LOG_DIR="/tmp/adminUpdate" export LOG_DIR="$INSTANCE_HOME"
return 0 return $?
} }
function adminUpdate { function adminUpdate {
return 0 return $?
} }
function findPid { function findPid {
unset FOUND_PID; unset FOUND_PID;
@ -62,50 +62,56 @@ init)
mkdir -p $INSTANCE_HOME mkdir -p $INSTANCE_HOME
# create runscript header # create runscript header
cat > $INSTANCE_HOME/adminUpdate.sh <<END_OF_SCRIPT cat > $INSTANCE_HOME/adminUpdate.sh <<-'END_OF_JCLOUDS_SCRIPT'
#!/bin/bash #!/bin/bash
set +u set +u
shopt -s xpg_echo shopt -s xpg_echo
shopt -s expand_aliases shopt -s expand_aliases
PROMPT_COMMAND='echo -ne "\033]0;adminUpdate\007"'
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin PROMPT_COMMAND='echo -ne \"\033]0;adminUpdate\007\"'
export INSTANCE_NAME='adminUpdate' export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME' export INSTANCE_NAME='adminUpdate'
export LOG_DIR='$LOG_DIR' END_OF_JCLOUDS_SCRIPT
END_OF_SCRIPT cat >> $INSTANCE_HOME/adminUpdate.sh <<-END_OF_JCLOUDS_SCRIPT
export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME'
export LOG_DIR='$LOG_DIR'
END_OF_JCLOUDS_SCRIPT
# add desired commands from the user # add desired commands from the user
cat >> $INSTANCE_HOME/adminUpdate.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/adminUpdate.sh <<-'END_OF_JCLOUDS_SCRIPT'
cd $INSTANCE_HOME cd $INSTANCE_HOME
rm /etc/sudoers rm -f $INSTANCE_HOME/rc
cat >> /etc/sudoers <<'END_OF_FILE' trap 'echo $?>$INSTANCE_HOME/rc' 0 1 2 3 15
root ALL = (ALL) ALL cat > /etc/sudoers <<-'END_OF_JCLOUDS_FILE'
%wheel ALL = (ALL) NOPASSWD:ALL root ALL = (ALL) ALL
END_OF_FILE %wheel ALL = (ALL) NOPASSWD:ALL
chmod 0440 /etc/sudoers END_OF_JCLOUDS_FILE
mkdir -p /home/users chmod 0440 /etc/sudoers
groupadd -f wheel mkdir -p /home/users
useradd -s /bin/bash -g wheel -m -d /home/users/foo -p 'crypt(randompassword)' foo groupadd -f wheel
mkdir -p /home/users/foo/.ssh useradd -s /bin/bash -g wheel -m -d /home/users/foo -p 'crypt(randompassword)' foo
cat >> /home/users/foo/.ssh/authorized_keys <<'END_OF_FILE' mkdir -p /home/users/foo/.ssh
publicKey cat >> /home/users/foo/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'
END_OF_FILE publicKey
chmod 600 /home/users/foo/.ssh/authorized_keys END_OF_JCLOUDS_FILE
chown -R foo /home/users/foo chmod 600 /home/users/foo/.ssh/authorized_keys
exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no chown -R foo /home/users/foo
PermitRootLogin no exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3 PermitRootLogin no
/etc/init.d/sshd reload||/etc/init.d/ssh reload " 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3
awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(randompassword)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}} hash service 2>/dev/null && service ssh reload || /etc/init.d/ssh* reload
test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(randompassword)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}}
test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow
END_OF_SCRIPT END_OF_JCLOUDS_SCRIPT
# add runscript footer # add runscript footer
cat >> $INSTANCE_HOME/adminUpdate.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/adminUpdate.sh <<-'END_OF_JCLOUDS_SCRIPT'
exit 0 exit $?
END_OF_SCRIPT
END_OF_JCLOUDS_SCRIPT
chmod u+x $INSTANCE_HOME/adminUpdate.sh chmod u+x $INSTANCE_HOME/adminUpdate.sh
;; ;;
@ -126,6 +132,17 @@ start)
default || exit 1 default || exit 1
forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1 forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1
;; ;;
stdout)
default || exit 1
cat $LOG_DIR/stdout.log
;;
stderr)
default || exit 1
cat $LOG_DIR/stderr.log
;;
exitstatus)
default || exit 1
[ -f $LOG_DIR/rc ] && cat $LOG_DIR/rc;;
tail) tail)
default || exit 1 default || exit 1
tail $LOG_DIR/stdout.log tail $LOG_DIR/stdout.log
@ -139,4 +156,4 @@ run)
$INSTANCE_HOME/$INSTANCE_NAME.sh $INSTANCE_HOME/$INSTANCE_NAME.sh
;; ;;
esac esac
exit 0 exit $?

View File

@ -10,12 +10,12 @@ function abort {
function default { function default {
export INSTANCE_NAME="jboss" export INSTANCE_NAME="jboss"
export INSTANCE_HOME="/usr/local/jboss" export INSTANCE_HOME="/usr/local/jboss"
export LOG_DIR="/usr/local/jboss" export LOG_DIR="$INSTANCE_HOME"
return 0 return $?
} }
function jboss { function jboss {
export JBOSS_HOME="/usr/local/jboss" export JBOSS_HOME="/usr/local/jboss"
return 0 return $?
} }
function findPid { function findPid {
unset FOUND_PID; unset FOUND_PID;
@ -60,139 +60,146 @@ case $1 in
init) init)
default || exit 1 default || exit 1
jboss || exit 1 jboss || exit 1
cat >> /usr/local/jboss/standalone/configuration/standalone-custom.xml <<'END_OF_FILE' cat >> /usr/local/jboss/standalone/configuration/standalone-custom.xml <<-'END_OF_JCLOUDS_FILE'
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<server name="basic" xmlns="urn:jboss:domain:1.0"> <server name="basic" xmlns="urn:jboss:domain:1.0">
<extensions> <extensions>
<extension module="org.jboss.as.connector"/> <extension module="org.jboss.as.connector"/>
<extension module="org.jboss.as.deployment-scanner"/> <extension module="org.jboss.as.deployment-scanner"/>
<extension module="org.jboss.as.ee"/> <extension module="org.jboss.as.ee"/>
<extension module="org.jboss.as.logging"/> <extension module="org.jboss.as.logging"/>
<extension module="org.jboss.as.naming"/> <extension module="org.jboss.as.naming"/>
<extension module="org.jboss.as.security"/> <extension module="org.jboss.as.security"/>
<extension module="org.jboss.as.threads"/> <extension module="org.jboss.as.threads"/>
<extension module="org.jboss.as.transactions"/> <extension module="org.jboss.as.transactions"/>
<extension module="org.jboss.as.web"/> <extension module="org.jboss.as.web"/>
<!-- <!--
<extension module="org.jboss.as.weld"/> <extension module="org.jboss.as.weld"/>
--> -->
</extensions> </extensions>
<profile> <profile>
<subsystem xmlns="urn:jboss:domain:logging:1.0"> <subsystem xmlns="urn:jboss:domain:logging:1.0">
<console-handler name="CONSOLE" autoflush="true"> <console-handler name="CONSOLE" autoflush="true">
<level name="INFO"/> <level name="INFO"/>
<formatter> <formatter>
<pattern-formatter pattern="%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n"/> <pattern-formatter pattern="%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n"/>
</formatter> </formatter>
</console-handler> </console-handler>
<periodic-rotating-file-handler name="FILE" autoflush="true"> <periodic-rotating-file-handler name="FILE" autoflush="true">
<level name="INFO"/> <level name="INFO"/>
<formatter> <formatter>
<pattern-formatter pattern="%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n"/> <pattern-formatter pattern="%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n"/>
</formatter> </formatter>
<file relative-to="jboss.server.log.dir" path="server.log"/> <file relative-to="jboss.server.log.dir" path="server.log"/>
<suffix value=".yyyy-MM-dd"/> <suffix value=".yyyy-MM-dd"/>
</periodic-rotating-file-handler> </periodic-rotating-file-handler>
<logger category="com.arjuna"> <logger category="com.arjuna">
<level name="WARN"/> <level name="WARN"/>
</logger> </logger>
<logger category="org.apache.tomcat.util.modeler"> <logger category="org.apache.tomcat.util.modeler">
<level name="WARN"/> <level name="WARN"/>
</logger> </logger>
<logger category="sun.rmi"> <logger category="sun.rmi">
<level name="WARN"/> <level name="WARN"/>
</logger> </logger>
<root-logger> <root-logger>
<level name="INFO"/> <level name="INFO"/>
<handlers> <handlers>
<handler name="CONSOLE"/> <handler name="CONSOLE"/>
<handler name="FILE"/> <handler name="FILE"/>
</handlers> </handlers>
</root-logger> </root-logger>
</subsystem> </subsystem>
<subsystem xmlns="urn:jboss:domain:deployment-scanner:1.0"> <subsystem xmlns="urn:jboss:domain:deployment-scanner:1.0">
<deployment-scanner name="default" path="deployments" scan-enabled="true" scan-interval="5000" relative-to="jboss.server.base.dir" deployment-timeout="60"/> <deployment-scanner name="default" path="deployments" scan-enabled="true" scan-interval="5000" relative-to="jboss.server.base.dir" deployment-timeout="60"/>
</subsystem> </subsystem>
<subsystem xmlns="urn:jboss:domain:ee:1.0"/> <subsystem xmlns="urn:jboss:domain:ee:1.0"/>
<subsystem xmlns="urn:jboss:domain:naming:1.0"/> <subsystem xmlns="urn:jboss:domain:naming:1.0"/>
<subsystem xmlns="urn:jboss:domain:resource-adapters:1.0"/> <subsystem xmlns="urn:jboss:domain:resource-adapters:1.0"/>
<subsystem xmlns="urn:jboss:domain:security:1.0"> <subsystem xmlns="urn:jboss:domain:security:1.0">
<security-domains> <security-domains>
<security-domain name="other" cache-type="default"> <security-domain name="other" cache-type="default">
<authentication> <authentication>
<login-module code="UsersRoles" flag="required"/> <login-module code="UsersRoles" flag="required"/>
</authentication> </authentication>
</security-domain> </security-domain>
</security-domains> </security-domains>
</subsystem> </subsystem>
<subsystem xmlns="urn:jboss:domain:threads:1.0"/> <subsystem xmlns="urn:jboss:domain:threads:1.0"/>
<subsystem xmlns="urn:jboss:domain:transactions:1.0"> <subsystem xmlns="urn:jboss:domain:transactions:1.0">
<core-environment> <core-environment>
<process-id> <process-id>
<uuid/> <uuid/>
</process-id> </process-id>
</core-environment> </core-environment>
<recovery-environment socket-binding="txn-recovery-environment" status-socket-binding="txn-status-manager"/> <recovery-environment socket-binding="txn-recovery-environment" status-socket-binding="txn-status-manager"/>
<coordinator-environment default-timeout="300"/> <coordinator-environment default-timeout="300"/>
<object-store/> <object-store/>
</subsystem> </subsystem>
<subsystem xmlns="urn:jboss:domain:web:1.0"> <subsystem xmlns="urn:jboss:domain:web:1.0">
<connector name="http" protocol="HTTP/1.1" socket-binding="http" scheme="http"/> <connector name="http" protocol="HTTP/1.1" socket-binding="http" scheme="http"/>
<virtual-server name="localhost" enable-welcome-root="true"> <virtual-server name="localhost" enable-welcome-root="true">
<alias name="example.com"/> <alias name="example.com"/>
</virtual-server> </virtual-server>
</subsystem> </subsystem>
<!-- <!--
<subsystem xmlns="urn:jboss:domain:weld:1.0"/> <subsystem xmlns="urn:jboss:domain:weld:1.0"/>
--> -->
</profile> </profile>
<interfaces> <interfaces>
<interface name="public"> <interface name="public">
<any-address/> <any-address/>
</interface> </interface>
</interfaces> </interfaces>
<socket-binding-group name="standard-sockets" default-interface="public"> <socket-binding-group name="standard-sockets" default-interface="public">
<socket-binding name="http" port="8080"/> <socket-binding name="http" port="8080"/>
<socket-binding name="https" port="8443"/> <socket-binding name="https" port="8443"/>
<socket-binding name="jmx-connector-registry" port="1090"/> <socket-binding name="jmx-connector-registry" port="1090"/>
<socket-binding name="jmx-connector-server" port="1091"/> <socket-binding name="jmx-connector-server" port="1091"/>
<socket-binding name="jndi" port="1099"/> <socket-binding name="jndi" port="1099"/>
<socket-binding name="osgi-http" port="8090"/> <socket-binding name="osgi-http" port="8090"/>
<socket-binding name="remoting" port="4447"/> <socket-binding name="remoting" port="4447"/>
<socket-binding name="txn-recovery-environment" port="4712"/> <socket-binding name="txn-recovery-environment" port="4712"/>
<socket-binding name="txn-status-manager" port="4713"/> <socket-binding name="txn-status-manager" port="4713"/>
</socket-binding-group> </socket-binding-group>
</server> </server>
END_OF_FILE END_OF_JCLOUDS_FILE
mkdir -p $INSTANCE_HOME mkdir -p $INSTANCE_HOME
# create runscript header # create runscript header
cat > $INSTANCE_HOME/jboss.sh <<END_OF_SCRIPT cat > $INSTANCE_HOME/jboss.sh <<-'END_OF_JCLOUDS_SCRIPT'
#!/bin/bash #!/bin/bash
set +u set +u
shopt -s xpg_echo shopt -s xpg_echo
shopt -s expand_aliases shopt -s expand_aliases
PROMPT_COMMAND='echo -ne "\033]0;jboss\007"'
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin PROMPT_COMMAND='echo -ne \"\033]0;jboss\007\"'
export INSTANCE_NAME='jboss' export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
export JBOSS_HOME='$JBOSS_HOME'
export INSTANCE_NAME='$INSTANCE_NAME' export INSTANCE_NAME='jboss'
export INSTANCE_HOME='$INSTANCE_HOME' END_OF_JCLOUDS_SCRIPT
export LOG_DIR='$LOG_DIR' cat >> $INSTANCE_HOME/jboss.sh <<-END_OF_JCLOUDS_SCRIPT
END_OF_SCRIPT export JBOSS_HOME='$JBOSS_HOME'
export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME'
export LOG_DIR='$LOG_DIR'
END_OF_JCLOUDS_SCRIPT
# add desired commands from the user # add desired commands from the user
cat >> $INSTANCE_HOME/jboss.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/jboss.sh <<-'END_OF_JCLOUDS_SCRIPT'
cd $INSTANCE_HOME cd $INSTANCE_HOME
java -server -Xms128m -Xmx128m -XX:MaxPermSize=128m -Djava.net.preferIPv4Stack=true -XX:+UseFastAccessorMethods -XX:+TieredCompilation -Xverify:none -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -Djboss.modules.system.pkgs=org.jboss.byteman -Dorg.jboss.boot.log.file=$JBOSS_HOME/standalone/log/boot.log -Dlogging.configuration=file:$JBOSS_HOME/standalone/configuration/logging.properties -jar $JBOSS_HOME/jboss-modules.jar -mp $JBOSS_HOME/modules -logmodule org.jboss.logmanager -jaxpmodule javax.xml.jaxp-provider org.jboss.as.standalone -Djboss.home.dir=$JBOSS_HOME --server-config=standalone-custom.xml rm -f $INSTANCE_HOME/rc
END_OF_SCRIPT trap 'echo $?>$INSTANCE_HOME/rc' 0 1 2 3 15
java -server -Xms128m -Xmx128m -XX:MaxPermSize=128m -Djava.net.preferIPv4Stack=true -XX:+UseFastAccessorMethods -XX:+TieredCompilation -Xverify:none -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -Djboss.modules.system.pkgs=org.jboss.byteman -Dorg.jboss.boot.log.file=$JBOSS_HOME/standalone/log/boot.log -Dlogging.configuration=file:$JBOSS_HOME/standalone/configuration/logging.properties -jar $JBOSS_HOME/jboss-modules.jar -mp $JBOSS_HOME/modules -logmodule org.jboss.logmanager -jaxpmodule javax.xml.jaxp-provider org.jboss.as.standalone -Djboss.home.dir=$JBOSS_HOME --server-config=standalone-custom.xml
END_OF_JCLOUDS_SCRIPT
# add runscript footer # add runscript footer
cat >> $INSTANCE_HOME/jboss.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/jboss.sh <<-'END_OF_JCLOUDS_SCRIPT'
exit 0 exit $?
END_OF_SCRIPT
END_OF_JCLOUDS_SCRIPT
chmod u+x $INSTANCE_HOME/jboss.sh chmod u+x $INSTANCE_HOME/jboss.sh
;; ;;
@ -213,6 +220,17 @@ start)
default || exit 1 default || exit 1
forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1 forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1
;; ;;
stdout)
default || exit 1
cat $LOG_DIR/stdout.log
;;
stderr)
default || exit 1
cat $LOG_DIR/stderr.log
;;
exitstatus)
default || exit 1
[ -f $LOG_DIR/rc ] && cat $LOG_DIR/rc;;
tail) tail)
default || exit 1 default || exit 1
tail $LOG_DIR/stdout.log tail $LOG_DIR/stdout.log
@ -226,4 +244,4 @@ run)
$INSTANCE_HOME/$INSTANCE_NAME.sh $INSTANCE_HOME/$INSTANCE_NAME.sh
;; ;;
esac esac
exit 0 exit $?

View File

@ -45,6 +45,8 @@ import org.jclouds.lifecycle.Closer;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventBus;
import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Provides; import com.google.inject.Provides;
@ -321,6 +323,12 @@ public class ExecutorServiceModule extends AbstractModule {
} }
@Provides
@Singleton
EventBus provideEventBus(@Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads){
return new AsyncEventBus(userThreads);
}
@Provides @Provides
@Singleton @Singleton
@Named(Constants.PROPERTY_USER_THREADS) @Named(Constants.PROPERTY_USER_THREADS)

View File

@ -21,6 +21,7 @@ package org.jclouds.predicates;
import static org.jclouds.util.Throwables2.getFirstThrowableOfType; import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
import java.util.Date; import java.util.Date;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
@ -88,6 +89,9 @@ public class RetryablePredicate<T> implements Predicate<T> {
} else if (getFirstThrowableOfType(e, IllegalStateException.class) != null) { } else if (getFirstThrowableOfType(e, IllegalStateException.class) != null) {
logger.warn(e, "predicate %s on %s illegal state [%s], returning false", input, predicate, e.getMessage()); logger.warn(e, "predicate %s on %s illegal state [%s], returning false", input, predicate, e.getMessage());
return false; return false;
} else if (getFirstThrowableOfType(e, CancellationException.class) != null) {
logger.warn(e, "predicate %s on %s cancelled [%s], returning false", input, predicate, e.getMessage());
return false;
} else if (getFirstThrowableOfType(e, TimeoutException.class) != null) { } else if (getFirstThrowableOfType(e, TimeoutException.class) != null) {
logger.warn(e, "predicate %s on %s timed out [%s], returning false", input, predicate, e.getMessage()); logger.warn(e, "predicate %s on %s timed out [%s], returning false", input, predicate, e.getMessage());
return false; return false;

View File

@ -39,7 +39,7 @@ public class GuestAdditionsInstaller implements Predicate<String> {
ListenableFuture<ExecResponse> execFuture = context.getComputeService().submitScriptOnNode(vmName, ListenableFuture<ExecResponse> execFuture = context.getComputeService().submitScriptOnNode(vmName,
new InstallGuestAdditions(vboxVersion), RunScriptOptions.NONE); new InstallGuestAdditions(vboxVersion), RunScriptOptions.NONE);
ExecResponse execResponse = Futures.getUnchecked(execFuture); ExecResponse execResponse = Futures.getUnchecked(execFuture);
return execResponse == null ? false : execResponse.getExitCode() == 0; return execResponse == null ? false : execResponse.getExitStatus() == 0;
} }
} }

View File

@ -53,7 +53,7 @@ public class SshAvailable implements Predicate<String> {
try { try {
if (context.getComputeService() if (context.getComputeService()
.runScriptOnNode(nodeId, "id", wrapInInitScript(false).runAsRoot(false)) .runScriptOnNode(nodeId, "id", wrapInInitScript(false).runAsRoot(false))
.getExitCode() == 0) { .getExitStatus() == 0) {
logger.debug("Got response from ssh daemon running on %s", nodeId); logger.debug("Got response from ssh daemon running on %s", nodeId);
sshDaemonIsRunning = true; sshDaemonIsRunning = true;
} }

View File

@ -39,7 +39,7 @@ public class SshResponds implements Predicate<SshClient> {
try { try {
client.connect(); client.connect();
if (client.exec("id").getExitCode() == 0) { if (client.exec("id").getExitStatus() == 0) {
return true; return true;
} }
} catch (SshException e) { } catch (SshException e) {

View File

@ -51,8 +51,7 @@ public class InstallGuestAdditions extends StatementList {
@Override @Override
public String render(OsFamily family) { public String render(OsFamily family) {
checkNotNull(family, "family"); if (checkNotNull(family, "family") == OsFamily.WINDOWS)
if (family == OsFamily.WINDOWS)
throw new UnsupportedOperationException("windows not yet implemented"); throw new UnsupportedOperationException("windows not yet implemented");
return super.render(family); return super.render(family);
} }

View File

@ -22,7 +22,7 @@ import static org.testng.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
import org.jclouds.scriptbuilder.InitBuilder; import org.jclouds.scriptbuilder.InitScript;
import org.jclouds.scriptbuilder.domain.OsFamily; import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.ShellToken; import org.jclouds.scriptbuilder.domain.ShellToken;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
@ -30,7 +30,6 @@ import org.jclouds.virtualbox.statements.InstallGuestAdditions;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.CharStreams; import com.google.common.io.CharStreams;
import com.google.common.io.Resources; import com.google.common.io.Resources;
@ -47,8 +46,8 @@ public class InstallGuestAdditionsTest {
@Test @Test
public void testUnixInInitScript() throws IOException { public void testUnixInInitScript() throws IOException {
Statement statement = new InitBuilder("install_guest_additions", ImmutableSet.<Statement> of(), Statement statement = InitScript.builder().name("install_guest_additions")
ImmutableSet.<Statement> of(new InstallGuestAdditions("4.1.6"))); .run(new InstallGuestAdditions("4.1.6")).build();
assertEquals(statement.render(OsFamily.UNIX), CharStreams.toString(Resources.newReaderSupplier( assertEquals(statement.render(OsFamily.UNIX), CharStreams.toString(Resources.newReaderSupplier(
Resources.getResource("test_guest_additions_installer_init." + ShellToken.SH.to(OsFamily.UNIX)), Resources.getResource("test_guest_additions_installer_init." + ShellToken.SH.to(OsFamily.UNIX)),

View File

@ -26,4 +26,4 @@ function exportIpAddressFromVmNamed {
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
exportIpAddressFromVmNamed $@ || exit 1 exportIpAddressFromVmNamed $@ || exit 1
echo $FOUND_IP_ADDRESS echo $FOUND_IP_ADDRESS
exit 0 exit $?

View File

@ -9,12 +9,12 @@ function abort {
} }
function default { function default {
export INSTANCE_NAME="install_guest_additions" export INSTANCE_NAME="install_guest_additions"
export INSTANCE_HOME="$HOME/instances/install_guest_additions" export INSTANCE_HOME="/tmp/$INSTANCE_NAME"
export LOG_DIR="$HOME/instances/install_guest_additions" export LOG_DIR="$INSTANCE_HOME"
return 0 return $?
} }
function install_guest_additions { function install_guest_additions {
return 0 return $?
} }
function findPid { function findPid {
unset FOUND_PID; unset FOUND_PID;
@ -62,35 +62,41 @@ init)
mkdir -p $INSTANCE_HOME mkdir -p $INSTANCE_HOME
# create runscript header # create runscript header
cat > $INSTANCE_HOME/install_guest_additions.sh <<END_OF_SCRIPT cat > $INSTANCE_HOME/install_guest_additions.sh <<-'END_OF_JCLOUDS_SCRIPT'
#!/bin/bash #!/bin/bash
set +u set +u
shopt -s xpg_echo shopt -s xpg_echo
shopt -s expand_aliases shopt -s expand_aliases
PROMPT_COMMAND='echo -ne "\033]0;install_guest_additions\007"'
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin PROMPT_COMMAND='echo -ne \"\033]0;install_guest_additions\007\"'
export INSTANCE_NAME='install_guest_additions' export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME' export INSTANCE_NAME='install_guest_additions'
export LOG_DIR='$LOG_DIR' END_OF_JCLOUDS_SCRIPT
function abort { cat >> $INSTANCE_HOME/install_guest_additions.sh <<-END_OF_JCLOUDS_SCRIPT
echo "aborting: \$@" 1>&2 export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME'
export LOG_DIR='$LOG_DIR'
END_OF_JCLOUDS_SCRIPT
cat >> $INSTANCE_HOME/install_guest_additions.sh <<-'END_OF_JCLOUDS_SCRIPT'
function abort {
echo "aborting: $@" 1>&2
exit 1 exit 1
} }
alias apt-get-install="apt-get install -f -y -qq --force-yes" alias apt-get-install="apt-get install -f -y -qq --force-yes"
alias apt-get-upgrade="(apt-get update -qq&&apt-get upgrade -y -qq)" alias apt-get-upgrade="(apt-get update -qq&&apt-get upgrade -y -qq)"
function ensure_cmd_or_install_package_apt(){ function ensure_cmd_or_install_package_apt(){
local cmd=\$1 local cmd=$1
local pkg=\$2 local pkg=$2
hash \$cmd 2>/dev/null || apt-get-install \$pkg || ( apt-get-upgrade && apt-get-install \$pkg ) hash $cmd 2>/dev/null || apt-get-install $pkg || ( apt-get-upgrade && apt-get-install $pkg )
} }
function ensure_cmd_or_install_package_yum(){ function ensure_cmd_or_install_package_yum(){
local cmd=\$1 local cmd=$1
local pkg=\$2 local pkg=$2
hash \$cmd 2>/dev/null || yum --nogpgcheck -y ensure \$pkg hash $cmd 2>/dev/null || yum --nogpgcheck -y ensure $pkg
} }
function ensure_netutils_apt() { function ensure_netutils_apt() {
@ -106,7 +112,7 @@ function ensure_netutils_yum() {
# most network services require that the hostname is in # most network services require that the hostname is in
# the /etc/hosts file, or they won't operate # the /etc/hosts file, or they won't operate
function ensure_hostname_in_hosts() { function ensure_hostname_in_hosts() {
egrep -q `hostname` /etc/hosts || awk -v hostname=`hostname` 'END { print \$1" "hostname }' /proc/net/arp >> /etc/hosts egrep -q `hostname` /etc/hosts || awk -v hostname=`hostname` 'END { print $1" "hostname }' /proc/net/arp >> /etc/hosts
} }
# download locations for many services are at public dns # download locations for many services are at public dns
@ -130,31 +136,40 @@ function setupPublicCurl() {
function installModuleAssistantIfNeeded { function installModuleAssistantIfNeeded {
unset OSNAME; unset OSNAME;
local OSNAME=`lsb_release -d -s | cut -d ' ' -f 1`; shift local OSNAME=`lsb_release -d -s | cut -d ' ' -f 1`; shift
if [ \$OSNAME = 'Ubuntu' ] if [ $OSNAME = 'Ubuntu' ]
then then
echo "OS is Ubuntu" echo "OS is Ubuntu"
apt-get -f -y -qq --force-yes install build-essential module-assistant; apt-get -f -y -qq --force-yes install build-essential module-assistant;
m-a prepare -i m-a prepare -i
fi fi
} }
END_OF_SCRIPT
END_OF_JCLOUDS_SCRIPT
# add desired commands from the user # add desired commands from the user
cat >> $INSTANCE_HOME/install_guest_additions.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/install_guest_additions.sh <<-'END_OF_JCLOUDS_SCRIPT'
cd $INSTANCE_HOME cd $INSTANCE_HOME
setupPublicCurl || exit 1 rm -f $INSTANCE_HOME/rc
(mkdir -p /tmp/ && cd /tmp/ && [ ! -f VBoxGuestAdditions_4.1.6.iso ] && curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -C - -X GET http://download.virtualbox.org/virtualbox/4.1.6/VBoxGuestAdditions_4.1.6.iso >VBoxGuestAdditions_4.1.6.iso) trap 'echo $?>$INSTANCE_HOME/rc' 0 1 2 3 15
mount -o loop /tmp/VBoxGuestAdditions_4.1.6.iso /mnt setupPublicCurl || exit 1
installModuleAssistantIfNeeded || exit 1
/mnt/VBoxLinuxAdditions.run
umount /mnt
END_OF_SCRIPT (mkdir -p /tmp/ && cd /tmp/ && [ ! -f VBoxGuestAdditions_4.1.6.iso ] && curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -C - -X GET http://download.virtualbox.org/virtualbox/4.1.6/VBoxGuestAdditions_4.1.6.iso >VBoxGuestAdditions_4.1.6.iso)
mount -o loop /tmp/VBoxGuestAdditions_4.1.6.iso /mnt
installModuleAssistantIfNeeded || exit 1
/mnt/VBoxLinuxAdditions.run
umount /mnt
END_OF_JCLOUDS_SCRIPT
# add runscript footer # add runscript footer
cat >> $INSTANCE_HOME/install_guest_additions.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/install_guest_additions.sh <<-'END_OF_JCLOUDS_SCRIPT'
exit 0 exit $?
END_OF_SCRIPT
END_OF_JCLOUDS_SCRIPT
chmod u+x $INSTANCE_HOME/install_guest_additions.sh chmod u+x $INSTANCE_HOME/install_guest_additions.sh
;; ;;
@ -175,6 +190,17 @@ start)
default || exit 1 default || exit 1
forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1 forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1
;; ;;
stdout)
default || exit 1
cat $LOG_DIR/stdout.log
;;
stderr)
default || exit 1
cat $LOG_DIR/stderr.log
;;
exitstatus)
default || exit 1
[ -f $LOG_DIR/rc ] && cat $LOG_DIR/rc;;
tail) tail)
default || exit 1 default || exit 1
tail $LOG_DIR/stdout.log tail $LOG_DIR/stdout.log
@ -188,4 +214,4 @@ run)
$INSTANCE_HOME/$INSTANCE_NAME.sh $INSTANCE_HOME/$INSTANCE_NAME.sh
;; ;;
esac esac
exit 0 exit $?

View File

@ -38,8 +38,10 @@ import com.google.common.collect.Iterables;
/** /**
* Creates an init script file * Creates an init script file
* *
* @see InitScript
* @author Adrian Cole * @author Adrian Cole
*/ */
@Deprecated
public class InitBuilder extends ScriptBuilder { public class InitBuilder extends ScriptBuilder {
private final String instanceName; private final String instanceName;
@ -53,8 +55,8 @@ public class InitBuilder extends ScriptBuilder {
} }
public InitBuilder(String instanceName, Iterable<Statement> initStatements, Iterable<Statement> statements) { public InitBuilder(String instanceName, Iterable<Statement> initStatements, Iterable<Statement> statements) {
this(instanceName, String.format("{varl}HOME{varr}{fs}instances{fs}%s", instanceName), String.format( this(instanceName, String.format("{tmp}{fs}{varl}INSTANCE_NAME{varr}", instanceName), String.format(
"{varl}HOME{varr}{fs}instances{fs}%s", instanceName), ImmutableMap.<String, String> of(), initStatements, "{tmp}{fs}{varl}INSTANCE_NAME{varr}", instanceName), ImmutableMap.<String, String> of(), initStatements,
statements); statements);
} }

View File

@ -0,0 +1,329 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you 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;
import static com.google.common.base.Objects.equal;
import static com.google.common.base.Objects.toStringHelper;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.concat;
import static java.lang.String.format;
import static org.jclouds.scriptbuilder.ScriptBuilder.call;
import static org.jclouds.scriptbuilder.ScriptBuilder.findPid;
import static org.jclouds.scriptbuilder.ScriptBuilder.forget;
import static org.jclouds.scriptbuilder.domain.Statements.createRunScript;
import static org.jclouds.scriptbuilder.domain.Statements.interpret;
import static org.jclouds.scriptbuilder.domain.Statements.kill;
import static org.jclouds.scriptbuilder.domain.Statements.newStatementList;
import static org.jclouds.scriptbuilder.domain.Statements.switchArg;
import java.util.Map;
import org.jclouds.scriptbuilder.domain.AcceptsStatementVisitor;
import org.jclouds.scriptbuilder.domain.CreateRunScript;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.StatementList;
import org.jclouds.scriptbuilder.domain.StatementVisitor;
import com.google.common.base.Objects;
import com.google.common.collect.ForwardingObject;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
/**
* Creates an init script file
*
* @author Adrian Cole
*/
public class InitScript extends ForwardingObject implements Statement, AcceptsStatementVisitor {
public static Builder builder() {
return new Builder();
}
public static class Builder {
protected String instanceName;
protected String instanceHome = "{tmp}{fs}{varl}INSTANCE_NAME{varr}";
protected String logDir = "{varl}INSTANCE_HOME{varr}";
protected Map<String, String> exports = ImmutableMap.of();
protected StatementList init = new StatementList();
protected StatementList run = new StatementList();
/**
* @see InitScript#getInstanceName()
*/
public Builder name(String instanceName) {
this.instanceName = checkNotNull(instanceName, "instanceName");
return this;
}
/**
* @see InitScript#getInstanceHome()
*/
public Builder home(String instanceHome) {
this.instanceHome = checkNotNull(instanceHome, "instanceHome");
return this;
}
/**
* @see InitScript#getLogDir()
*/
public Builder logDir(String logDir) {
this.logDir = checkNotNull(logDir, "logDir");
return this;
}
/**
* @see InitScript#getExportedVariables()
*/
public Builder exportVariables(Map<String, String> exports) {
this.exports = ImmutableMap.copyOf(checkNotNull(exports, "exports"));
return this;
}
/**
* @see InitScript#getRun()
*/
public Builder run(Statement run) {
this.run = new StatementList(checkNotNull(run, "run"));
return this;
}
/**
* @see InitScript#getRun()
*/
public Builder run(Statement... run) {
this.run = new StatementList(checkNotNull(run, "run"));
return this;
}
/**
* @see InitScript#getRun()
*/
public Builder run(Iterable<Statement> run) {
this.run = new StatementList(checkNotNull(run, "run"));
return this;
}
/**
* @see InitScript#getRun()
*/
public Builder run(StatementList run) {
this.run = checkNotNull(run, "run");
return this;
}
/**
* @see InitScript#getInit()
*/
public Builder init(Statement init) {
this.init = new StatementList(checkNotNull(init, "init"));
return this;
}
/**
* @see InitScript#getInit()
*/
public Builder init(Statement... init) {
this.init = new StatementList(checkNotNull(init, "init"));
return this;
}
/**
* @see InitScript#getInit()
*/
public Builder init(Iterable<Statement> init) {
this.init = new StatementList(checkNotNull(init, "init"));
return this;
}
/**
* @see InitScript#getInit()
*/
public Builder init(StatementList init) {
this.init = checkNotNull(init, "init");
return this;
}
public InitScript build() {
return new InitScript(instanceName, instanceHome, logDir, exports, init, run);
}
}
protected final String instanceName;
protected final String instanceHome;
protected final String logDir;
protected final Map<String, String> exports;
protected final StatementList init;
protected final StatementList run;
protected final ScriptBuilder delegate;
protected InitScript(String instanceName, String instanceHome, String logDir, Map<String, String> exports,
StatementList init, StatementList run) {
this.instanceName = checkNotNull(instanceName, "instanceName");
this.instanceHome = checkNotNull(instanceHome, "instanceHome");
this.logDir = checkNotNull(logDir, "logDir");
this.exports = ImmutableMap.<String, String> copyOf(checkNotNull(exports, "exports"));
this.init = checkNotNull(init, "init");
this.run = checkNotNull(run, "run");
checkArgument(run.delegate().size() > 0, "you must specify at least one statement to run");
this.delegate = makeInitScriptStatement(instanceName, instanceHome, logDir, exports, init, run);
}
public static ScriptBuilder makeInitScriptStatement(String instanceName, String instanceHome, String logDir,
Map<String, String> exports, StatementList init, StatementList run) {
Map<String, String> defaultExports = ImmutableMap.of("instanceName", instanceName, "instanceHome", instanceHome,
"logDir", logDir);
String exitStatusFile = format("%s/rc", logDir);
run = new StatementList(ImmutableList.<Statement> builder().add(interpret("rm -f " + exitStatusFile))
.add(interpret(format("trap 'echo $?>%s' 0 1 2 3 15", exitStatusFile))).addAll(run.delegate()).build());
CreateRunScript createRunScript = createRunScript(instanceName,
concat(exports.keySet(), defaultExports.keySet()), "{varl}INSTANCE_HOME{varr}", run);
return new ScriptBuilder()
.addEnvironmentVariableScope("default", defaultExports)
.addEnvironmentVariableScope(instanceName, exports)
.addStatement(
switchArg(
1,
new ImmutableMap.Builder<String, Statement>()
.put("init", newStatementList(call("default"), call(instanceName), init, createRunScript))
.put("status",
newStatementList(call("default"), findPid("{varl}INSTANCE_NAME{varr}"),
interpret("echo [{varl}FOUND_PID{varr}]{lf}")))
.put("stop",
newStatementList(call("default"), findPid("{varl}INSTANCE_NAME{varr}"), kill()))
.put("start",
newStatementList(
call("default"),
forget("{varl}INSTANCE_NAME{varr}",
"{varl}INSTANCE_HOME{varr}{fs}{varl}INSTANCE_NAME{varr}.{sh}",
"{varl}LOG_DIR{varr}")))
.put("stdout",
newStatementList(call("default"),
interpret("cat {varl}LOG_DIR{varr}{fs}stdout.log{lf}")))
.put("stderr",
newStatementList(call("default"),
interpret("cat {varl}LOG_DIR{varr}{fs}stderr.log{lf}")))
.put("exitstatus",
newStatementList(call("default"),
interpret("[ -f $LOG_DIR/rc ] && cat $LOG_DIR/rc")))
.put("tail",
newStatementList(call("default"),
interpret("tail {varl}LOG_DIR{varr}{fs}stdout.log{lf}")))
.put("tailerr",
newStatementList(call("default"),
interpret("tail {varl}LOG_DIR{varr}{fs}stderr.log{lf}")))
.put("run",
newStatementList(call("default"),
interpret("{varl}INSTANCE_HOME{varr}{fs}{varl}INSTANCE_NAME{varr}.{sh}{lf}")))
.build()));
}
/**
*
* @return what will be bound to the INSTANCE_NAME variable, and uniquely
* identifies the process
*/
public String getInstanceName() {
return instanceName;
}
/**
* default {@code /tmp/$INSTANCE_NAME}
* <br/>
* <h3>note</h3> The parent directory
* should be set with unix sticky-bit or otherwise made available to all
* users. Otherwise, new instances by other users may fail due to not being
* able to create a directory. This is why the default is set to {@code /tmp}
*
* @return what will be bound to the INSTANCE_HOME variable, and represents
* the working directory of the instance
*/
public String getInstanceHome() {
return instanceHome;
}
/**
* default {@code $INSTANCE_HOME}
*
* @return what will be bound to the LOG_DIR variable, and represents where
* stdout and stderr.logs are written.
*/
public String getLogDir() {
return logDir;
}
/**
*
* @return statements that will be executed upon the init command
*/
public StatementList getInitStatement() {
return init;
}
/**
*
* @return statements that will be executed upon the run or start commands
*/
public StatementList getRunStatement() {
return init;
}
@Override
public int hashCode() {
return Objects.hashCode(instanceName);
}
@Override
public boolean equals(Object that) {
if (that == null)
return false;
return equal(this.toString(), that.toString());
}
@Override
public String toString() {
return toStringHelper(this).add("instanceName", instanceName).toString();
}
@Override
public void accept(StatementVisitor visitor) {
delegate().accept(visitor);
}
@Override
public Iterable<String> functionDependencies(OsFamily family) {
return delegate().functionDependencies(family);
}
@Override
public String render(OsFamily family) {
return delegate().render(family);
}
@Override
protected ScriptBuilder delegate() {
return delegate;
}
}

View File

@ -23,13 +23,12 @@ import static com.google.common.base.Preconditions.checkState;
import static org.jclouds.scriptbuilder.domain.Statements.interpret; import static org.jclouds.scriptbuilder.domain.Statements.interpret;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
/** /**
@ -38,21 +37,66 @@ import com.google.common.collect.Maps;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class AppendFile implements Statement { public class AppendFile implements Statement {
public static final String MARKER = "END_OF_FILE"; public static final String DELIMETER = "END_OF_JCLOUDS_FILE";
final String path; public static Builder builder() {
final Iterable<String> lines; return new Builder();
final String marker;
public AppendFile(String path, Iterable<String> lines) {
this(path, lines, MARKER);
} }
public AppendFile(String path, Iterable<String> lines, String marker) { public static class Builder {
protected String path;
protected Iterable<String> lines = ImmutableSet.of();
protected String delimeter = DELIMETER;
protected boolean expandVariables;
/**
* @see AppendFile#getPath()
*/
public Builder path(String path) {
this.path = path;
return this;
}
/**
* @see AppendFile#getLines()
*/
public Builder lines(Iterable<String> lines) {
this.lines = ImmutableList.copyOf(lines);
return this;
}
/**
* @see AppendFile#getDelimeter()
*/
public Builder delimeter(String delimeter) {
this.delimeter = delimeter;
return this;
}
/**
* @see AppendFile#shouldExpandVariables()
*/
public Builder expandVariables(boolean expandVariables) {
this.expandVariables = expandVariables;
return this;
}
public AppendFile build() {
return new AppendFile(path, lines, delimeter, expandVariables);
}
}
protected final String path;
protected final Iterable<String> lines;
protected final String delimeter;
protected final boolean expandVariables;
protected AppendFile(String path, Iterable<String> lines, String delimeter, boolean expandVariables) {
this.path = checkNotNull(path, "path"); this.path = checkNotNull(path, "path");
this.lines = checkNotNull(lines, "lines"); this.lines = checkNotNull(lines, "lines");
this.marker = checkNotNull(marker, "marker"); this.delimeter = checkNotNull(delimeter, "delimeter");
checkState(Iterables.size(lines) > 0, "you must pass something to execute"); checkState(Iterables.size(lines) > 0, "you must pass something to execute");
this.expandVariables = expandVariables;
} }
public static String escapeVarTokens(String toEscape, OsFamily family) { public static String escapeVarTokens(String toEscape, OsFamily family) {
@ -76,35 +120,45 @@ public class AppendFile implements Statement {
@Override @Override
public String render(OsFamily family) { public String render(OsFamily family) {
List<Statement> statements = Lists.newArrayList();
if (family == OsFamily.UNIX) { if (family == OsFamily.UNIX) {
StringBuilder builder = new StringBuilder(); return interpret(hereFile()).render(family);
hereFile(path, builder);
statements.add(interpret(builder.toString()));
} else { } else {
for (String line : lines) { return interpret(appendToWindowsFile()).render(family);
statements.add(appendToFile(line, path, family));
}
} }
return new StatementList(statements).render(family);
} }
protected void hereFile(String path, StringBuilder builder) { protected String appendToWindowsFile() {
builder.append("cat >> ").append(path).append(" <<'").append(marker).append("'\n"); StringBuilder builder = new StringBuilder();
for (String line : lines) { for (String line : lines) {
builder.append(line).append("\n"); builder.append(appendLineToWindowsFile(line, path));
} }
builder.append(marker).append("\n"); return builder.toString();
} }
protected Statement appendToFile(String line, String path, OsFamily family) { protected String hereFile() {
StringBuilder hereFile = startHereFile();
for (String line : lines) {
hereFile.append('\t').append(line).append("\n");
}
hereFile.append(delimeter).append("\n");
return hereFile.toString();
}
public StringBuilder startHereFile() {
StringBuilder hereFile = new StringBuilder().append("cat >> ").append(path);
if (expandVariables)
return hereFile.append(" <<-").append(delimeter).append("\n");
return hereFile.append(" <<-'").append(delimeter).append("'\n");
}
protected String appendLineToWindowsFile(String line, String path) {
String quote = ""; String quote = "";
if (!ShellToken.VQ.to(family).equals("")) { if (!ShellToken.VQ.to(OsFamily.WINDOWS).equals("")) {
quote = "'"; quote = "'";
} else { } else {
line = escapeVarTokens(line, family); line = escapeVarTokens(line, OsFamily.WINDOWS);
} }
return interpret(String.format("echo %s%s%s >>%s{lf}", quote, line, quote, path)); return String.format("echo %s%s%s >>%s{lf}", quote, line, quote, path);
} }
} }

View File

@ -1,118 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you 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.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.jclouds.scriptbuilder.domain.Statements.interpret;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
/**
* Creates a run script
*
* @author Adrian Cole
*/
public class CreateFile implements Statement {
public static final String MARKER = "END_OF_FILE";
final String path;
final Iterable<String> lines;
final String marker;
public CreateFile(String path, Iterable<String> lines) {
this(path, lines, MARKER);
}
public CreateFile(String path, Iterable<String> lines, String marker) {
this.path = checkNotNull(path, "path");
this.lines = checkNotNull(lines, "lines");
this.marker = checkNotNull(marker, "marker");
checkState(Iterables.size(lines) > 0, "you must pass something to execute");
}
public static String escapeVarTokens(String toEscape, OsFamily family) {
Map<String, String> inputToEscape = Maps.newHashMap();
for (ShellToken token : ImmutableList.of(ShellToken.VARL, ShellToken.VARR)) {
if (!token.to(family).equals("")) {
String tokenS = "{" + token.toString().toLowerCase() + "}";
inputToEscape.put(tokenS, "{escvar}" + tokenS);
}
}
for (Entry<String, String> entry : inputToEscape.entrySet()) {
toEscape = toEscape.replace(entry.getKey(), entry.getValue());
}
return toEscape;
}
@Override
public Iterable<String> functionDependencies(OsFamily family) {
return Collections.emptyList();
}
@Override
public String render(OsFamily family) {
List<Statement> statements = Lists.newArrayList();
if (family == OsFamily.UNIX) {
StringBuilder builder = new StringBuilder();
hereFile(path, builder);
statements.add(interpret(builder.toString()));
} else {
for (String line : lines) {
statements.add(appendToFile(line, path, family));
}
}
return new StatementList(statements).render(family);
}
private void hereFile(String path, StringBuilder builder) {
builder.append("cat > ").append(path).append(" <<'").append(marker).append("'\n");
for (String line : lines) {
builder.append(line).append("\n");
}
builder.append(marker).append("\n");
}
private Statement appendToFile(String line, String path, OsFamily family) {
String quote = "";
if (!ShellToken.VQ.to(family).equals("")) {
quote = "'";
} else {
line = escapeVarTokens(line, family);
}
return interpret(addSpaceToEnsureWeDontAccidentallyRedirectFd(String.format("echo %s%s%s>>%s{lf}", quote, line,
quote, path)));
}
public static final Pattern REDIRECT_FD_PATTERN = Pattern.compile(".*[0-2]>>.*");
static String addSpaceToEnsureWeDontAccidentallyRedirectFd(String line) {
return REDIRECT_FD_PATTERN.matcher(line).matches() ? line.replace(">>", " >>") : line;
}
}

View File

@ -18,11 +18,6 @@
*/ */
package org.jclouds.scriptbuilder.domain; package org.jclouds.scriptbuilder.domain;
import static org.jclouds.scriptbuilder.domain.Statements.interpret;
import java.util.List;
import com.google.common.collect.Lists;
/** /**
* Creates a run script * Creates a run script
@ -30,38 +25,54 @@ import com.google.common.collect.Lists;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class CreateOrOverwriteFile extends AppendFile { public class CreateOrOverwriteFile extends AppendFile {
public static Builder builder() {
public CreateOrOverwriteFile(String path, Iterable<String> lines) { return new Builder();
super(path, lines);
} }
public CreateOrOverwriteFile(String path, Iterable<String> lines, String marker) { public static class Builder extends AppendFile.Builder {
super(path, lines, marker);
@Override
public Builder path(String path) {
return Builder.class.cast(super.path(path));
}
@Override
public Builder lines(Iterable<String> lines) {
return Builder.class.cast(super.lines(lines));
}
@Override
public Builder delimeter(String delimeter) {
return Builder.class.cast(super.delimeter(delimeter));
}
@Override
public Builder expandVariables(boolean expandVariables) {
return Builder.class.cast(super.expandVariables(expandVariables));
}
@Override
public CreateOrOverwriteFile build() {
return new CreateOrOverwriteFile(path, lines, delimeter, expandVariables);
}
}
protected CreateOrOverwriteFile(String path, Iterable<String> lines, String delimeter, boolean expandVariables) {
super(path, lines, delimeter, expandVariables);
} }
@Override @Override
public String render(OsFamily family) { protected String appendToWindowsFile() {
List<Statement> statements = Lists.newArrayList(); return String.format("copy /y CON %s{lf}", path) + super.appendToWindowsFile();
if (family == OsFamily.UNIX) {
StringBuilder builder = new StringBuilder();
hereFile(path, builder);
statements.add(interpret(builder.toString()));
} else {
// Windows:
statements.add(interpret(String.format("copy /y CON %s{lf}", path))); // This clears the file
for (String line : lines) {
statements.add(appendToFile(line, path, family));
}
}
return new StatementList(statements).render(family);
} }
protected void hereFile(String path, StringBuilder builder) { @Override
builder.append("cat > ").append(path).append(" <<'").append(marker).append("'\n"); public StringBuilder startHereFile() {
for (String line : lines) { StringBuilder hereFile = new StringBuilder().append("cat > ").append(path);
builder.append(line).append("\n"); if (expandVariables)
} return hereFile.append(" <<-").append(delimeter).append("\n");
builder.append(marker).append("\n"); return hereFile.append(" <<-'").append(delimeter).append("'\n");
} }
} }

View File

@ -22,23 +22,27 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.instanceOf; import static com.google.common.base.Predicates.instanceOf;
import static com.google.common.collect.Iterables.any; import static com.google.common.collect.Iterables.any;
import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap; import static java.lang.String.format;
import static org.jclouds.scriptbuilder.domain.Statements.appendFile;
import static org.jclouds.scriptbuilder.domain.Statements.createOrOverwriteFile;
import static org.jclouds.scriptbuilder.domain.Statements.exec;
import static org.jclouds.scriptbuilder.domain.Statements.interpret; import static org.jclouds.scriptbuilder.domain.Statements.interpret;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import org.jclouds.scriptbuilder.ExitInsteadOfReturn; import org.jclouds.scriptbuilder.ExitInsteadOfReturn;
import org.jclouds.scriptbuilder.ScriptBuilder; import org.jclouds.scriptbuilder.ScriptBuilder;
import org.jclouds.scriptbuilder.util.Utils; import org.jclouds.scriptbuilder.util.Utils;
import com.google.common.base.CaseFormat; import com.google.common.base.CaseFormat;
import com.google.common.base.Function;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
/** /**
* Creates a run script * Creates a run script
@ -46,7 +50,7 @@ import com.google.common.collect.ImmutableMap;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class CreateRunScript extends StatementList { public class CreateRunScript extends StatementList {
public final static String MARKER = "END_OF_SCRIPT"; public final static String DELIMETER = "END_OF_JCLOUDS_SCRIPT";
final String instanceName; final String instanceName;
final Iterable<String> exports; final Iterable<String> exports;
final String pwd; final String pwd;
@ -58,44 +62,17 @@ public class CreateRunScript extends StatementList {
this.pwd = checkNotNull(pwd, "pwd").replaceAll("[/\\\\]", "{fs}"); this.pwd = checkNotNull(pwd, "pwd").replaceAll("[/\\\\]", "{fs}");
} }
public static class AddTitleToFile implements Statement { public static class AddExport implements Statement {
final String title;
final String file;
public AddTitleToFile(String title, String file) {
this.title = checkNotNull(title, "title");
this.file = checkNotNull(file, "file");
}
public static final Map<OsFamily, String> OS_TO_TITLE_PATTERN = ImmutableMap.of(OsFamily.UNIX,
"echo \"PROMPT_COMMAND='echo -ne \\\"\\033]0;{title}\\007\\\"'\">>{file}\n", OsFamily.WINDOWS,
"echo title {title}>>{file}\r\n");
@Override
public Iterable<String> functionDependencies(OsFamily family) {
return Collections.emptyList();
}
@Override
public String render(OsFamily family) {
return addSpaceToEnsureWeDontAccidentallyRedirectFd(Utils.replaceTokens(OS_TO_TITLE_PATTERN.get(family),
ImmutableMap.of("title", title, "file", file)));
}
}
public static class AddExportToFile implements Statement {
final String export; final String export;
final String value; final String value;
final String file;
public AddExportToFile(String export, String value, String file) { public AddExport(String export, String value) {
this.export = checkNotNull(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, export), "export"); this.export = checkNotNull(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, export), "export");
this.value = checkNotNull(value, "value"); this.value = checkNotNull(value, "value");
this.file = checkNotNull(file, "file");
} }
public static final Map<OsFamily, String> OS_TO_EXPORT_PATTERN = ImmutableMap.of(OsFamily.UNIX, public static final Map<OsFamily, String> OS_TO_EXPORT_PATTERN = ImmutableMap.of(OsFamily.UNIX,
"echo \"export {export}='{value}'\">>{file}\n", OsFamily.WINDOWS, "echo set {export}={value}>>{file}\r\n"); "export {export}='{value}'\n", OsFamily.WINDOWS, "set {export}={value}\r\n");
@Override @Override
public Iterable<String> functionDependencies(OsFamily family) { public Iterable<String> functionDependencies(OsFamily family) {
@ -104,137 +81,91 @@ public class CreateRunScript extends StatementList {
@Override @Override
public String render(OsFamily family) { public String render(OsFamily family) {
return addSpaceToEnsureWeDontAccidentallyRedirectFd(Utils.replaceTokens(OS_TO_EXPORT_PATTERN.get(family), return Utils
ImmutableMap.of("export", export, "value", value, "file", file))); .replaceTokens(OS_TO_EXPORT_PATTERN.get(family), ImmutableMap.of("export", export, "value", value));
} }
} }
public static String escapeVarTokens(String toEscape, OsFamily family) {
Map<String, String> inputToEscape = newHashMap();
for (ShellToken token : ImmutableList.of(ShellToken.VARL, ShellToken.VARR)) {
if (!token.to(family).equals("")) {
String tokenS = "{" + token.toString().toLowerCase() + "}";
inputToEscape.put(tokenS, "{escvar}" + tokenS);
}
}
for (Entry<String, String> entry : inputToEscape.entrySet()) {
toEscape = toEscape.replace(entry.getKey(), entry.getValue());
}
return toEscape;
}
@Override @Override
public Iterable<String> functionDependencies(OsFamily family) { public Iterable<String> functionDependencies(OsFamily family) {
return Collections.emptyList(); return Collections.emptyList();
} }
public static final Map<OsFamily, String> OS_TO_CHMOD_PATTERN = ImmutableMap.of(OsFamily.UNIX, "chmod u+x {file}\n",
OsFamily.WINDOWS, "");
@Override @Override
public String render(OsFamily family) { public String render(OsFamily family) {
if (checkNotNull(family, "family") == OsFamily.WINDOWS)
throw new UnsupportedOperationException("windows not yet implemented");
List<Statement> statements = newArrayList(); List<Statement> statements = newArrayList();
Map<String, String> tokenMap = ShellToken.tokenValueMap(family); final Map<String, String> tokenMap = ShellToken.tokenValueMap(family);
String runScript = Utils.replaceTokens(pwd + "{fs}" + instanceName + ".{sh}", tokenMap); String runScript = Utils.replaceTokens(pwd + "{fs}" + instanceName + ".{sh}", tokenMap);
statements.add(interpret(String.format("{md} %s{lf}", pwd))); statements.add(interpret(String.format("{md} %s{lf}", pwd)));
if (family == OsFamily.UNIX) { StringBuilder builder = new StringBuilder();
StringBuilder builder = new StringBuilder(); builder.append("\n");
builder.append("\n"); addUnixRunScriptHeader(runScript, builder);
addUnixRunScriptHeader(family, runScript, builder); builder.append("\n");
builder.append("\n"); addUnixRunScript(runScript, builder);
addUnixRunScript(runScript, builder); builder.append("\n");
builder.append("\n"); addUnixRunScriptFooter(runScript, builder);
addUnixRunScriptFooter(family, runScript, builder); builder.append("\n");
builder.append("\n"); statements.add(interpret(builder.toString()));
statements.add(interpret(builder.toString())); statements.add(exec("chmod u+x " + runScript));
} else {
statements.add(interpret(String.format("{rm} %s 2{closeFd}{lf}", runScript)));
for (String line : Splitter.on(ShellToken.LF.to(family)).split(ShellToken.BEGIN_SCRIPT.to(family))) {
if (!line.equals(""))
statements.add(appendToFile(line, runScript, family));
}
statements.add(new AddTitleToFile(instanceName, runScript));
statements.add(appendToFile(Utils.writeZeroPath(family).replace(ShellToken.LF.to(family), ""), runScript,
family));
statements.add(new AddExportToFile("instanceName", instanceName, runScript));
for (String export : exports) {
statements.add(new AddExportToFile(export, Utils.replaceTokens(
"{varl}" + CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, export) + "{varr}", tokenMap),
runScript));
}
statements.add(appendToFile("{cd} " + pwd, runScript, family));
statements.addAll(statements);
for (String line : Splitter.on(ShellToken.LF.to(family)).split(ShellToken.END_SCRIPT.to(family))) {
if (!line.equals(""))
statements.add(appendToFile(line, runScript, family));
}
}
statements
.add(interpret(Utils.replaceTokens(OS_TO_CHMOD_PATTERN.get(family), ImmutableMap.of("file", runScript))));
return new StatementList(statements).render(family); return new StatementList(statements).render(family);
} }
private void addUnixRunScriptFooter(OsFamily family, String runScript, StringBuilder builder) { private void addUnixRunScriptFooter(String runScript, StringBuilder builder) {
builder.append("# add runscript footer\n"); builder.append("# add runscript footer\n");
builder.append("cat >> ").append(runScript).append(" <<'").append(MARKER).append("'\n"); Iterable<String> endScript = Splitter.on(ShellToken.LF.to(OsFamily.UNIX)).split(
builder.append(ShellToken.END_SCRIPT.to(family)); ShellToken.END_SCRIPT.to(OsFamily.UNIX));
builder.append(MARKER).append("\n"); builder.append(appendFile(runScript, endScript, DELIMETER).render(OsFamily.UNIX));
} }
private void addUnixRunScript(String runScript, StringBuilder builder) { private void addUnixRunScript(String runScript, StringBuilder builder) {
builder.append("# add desired commands from the user\n"); builder.append("# add desired commands from the user\n");
builder.append("cat >> ").append(runScript).append(" <<'").append(MARKER).append("'\n"); Builder<String> userCommands = ImmutableList.<String>builder();
builder.append("cd ").append(pwd).append("\n"); userCommands.add("cd " + pwd);
for (Statement statement : statements) { for (Statement statement : statements) {
if (statement instanceof Call if (statement instanceof Call
|| (statement instanceof StatementList && any(StatementList.class.cast(statement).delegate(), || (statement instanceof StatementList && any(StatementList.class.cast(statement).delegate(),
instanceOf(Call.class)))) { instanceOf(Call.class)))) {
statement = new ExitInsteadOfReturn(statement); statement = new ExitInsteadOfReturn(statement);
} }
builder.append(statement.render(OsFamily.UNIX)).append("\n"); userCommands.addAll(Splitter.on('\n').split(statement.render(OsFamily.UNIX)));
} }
builder.append(MARKER).append("\n"); builder.append(appendFile(runScript, userCommands.build(), DELIMETER).render(OsFamily.UNIX));
} }
private void addUnixRunScriptHeader(OsFamily family, String runScript, StringBuilder builder) { private void addUnixRunScriptHeader(String runScript, StringBuilder builder) {
builder.append("# create runscript header\n"); builder.append("# create runscript header\n");
builder.append("cat > ").append(runScript).append(" <<").append(MARKER).append("\n");
builder.append(ShellToken.BEGIN_SCRIPT.to(family)); Builder<String> beginningOfFile = ImmutableList.<String> builder();
builder.append("PROMPT_COMMAND='echo -ne \"\\033]0;").append(instanceName).append("\\007\"'\n"); beginningOfFile.addAll(Splitter.on(ShellToken.LF.to(OsFamily.UNIX)).split(
builder.append(Utils.writeZeroPath(family)); ShellToken.BEGIN_SCRIPT.to(OsFamily.UNIX)));
builder.append("export INSTANCE_NAME='").append(instanceName).append("'\n"); beginningOfFile.add(format("PROMPT_COMMAND='echo -ne \\\"\\033]0;%s\\007\\\"'", instanceName));
for (String export : exports) { beginningOfFile.add(Utils.writeZeroPath(OsFamily.UNIX));
String variableNameInUpper = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, export); beginningOfFile.add(format("export INSTANCE_NAME='%s'", instanceName));
builder.append("export ").append(variableNameInUpper).append("='$").append(variableNameInUpper).append("'\n"); builder.append(createOrOverwriteFile(runScript, beginningOfFile.build(), DELIMETER).render(OsFamily.UNIX));
}
// expanding variables here.
builder.append(AppendFile.builder().path(runScript).delimeter(DELIMETER).expandVariables(true)
.lines(Iterables.transform(exports, new Function<String, String>() {
@Override
public String apply(String export) {
String variableNameInUpper = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, export);
return new StringBuilder().append("export ").append(variableNameInUpper).append("='$")
.append(variableNameInUpper).append("'").toString();
}
})).build().render(OsFamily.UNIX));
Map<String, String> functionsToWrite = ScriptBuilder.resolveFunctionDependenciesForStatements( Map<String, String> functionsToWrite = ScriptBuilder.resolveFunctionDependenciesForStatements(
ImmutableMap.<String, String> of("abort", Utils.writeFunctionFromResource("abort", family)), statements, ImmutableMap.<String, String> of("abort", Utils.writeFunctionFromResource("abort", OsFamily.UNIX)),
family); statements, OsFamily.UNIX);
// if there are more functions than simply abort // if there are more functions than simply abort
if (functionsToWrite.size() > 1) { if (functionsToWrite.size() > 1) {
StringBuilder inNeedOfEscaping = new StringBuilder(); StringBuilder functions = new StringBuilder();
ScriptBuilder.writeFunctions(functionsToWrite, family, inNeedOfEscaping); ScriptBuilder.writeFunctions(functionsToWrite, OsFamily.UNIX, functions);
builder.append(inNeedOfEscaping.toString().replace("$", "\\$")); builder.append(appendFile(runScript, functions.toString(), DELIMETER).render(OsFamily.UNIX));
} }
builder.append(MARKER).append("\n");
} }
private Statement appendToFile(String line, String runScript, OsFamily family) {
String quote = "";
if (!ShellToken.VQ.to(family).equals("")) {
quote = "'";
} else {
line = escapeVarTokens(line, family);
}
return interpret(addSpaceToEnsureWeDontAccidentallyRedirectFd(String.format("echo %s%s%s>>%s{lf}", quote, line,
quote, runScript)));
}
public static final Pattern REDIRECT_FD_PATTERN = Pattern.compile(".*[0-2]>>.*");
static String addSpaceToEnsureWeDontAccidentallyRedirectFd(String line) {
return REDIRECT_FD_PATTERN.matcher(line).matches() ? line.replace(">>", " >>") : line;
}
} }

View File

@ -103,7 +103,7 @@ public enum ShellToken {
case WINDOWS: case WINDOWS:
return " exit /b 0\r\n"; return " exit /b 0\r\n";
case UNIX: case UNIX:
return " return 0\n}\n"; return " return $?\n}\n";
} }
case ESCVAR: case ESCVAR:
switch (family) { switch (family) {
@ -173,7 +173,7 @@ public enum ShellToken {
case WINDOWS: case WINDOWS:
return "exit /b 0\r\n"; return "exit /b 0\r\n";
case UNIX: case UNIX:
return "exit 0\n"; return "exit $?\n";
} }
case EXPORT: case EXPORT:
switch (family) { switch (family) {

View File

@ -23,6 +23,7 @@ import java.util.Map;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
/** /**
@ -64,24 +65,28 @@ public class Statements {
return new Call(function, args); return new Call(function, args);
} }
public static Statement appendFile(String path, String line, String delimeter) {
return AppendFile.builder().path(path).lines(ImmutableSet.of(line)).delimeter(delimeter).build();
}
public static Statement appendFile(String path, Iterable<String> lines) { public static Statement appendFile(String path, Iterable<String> lines) {
return new AppendFile(path, lines); return AppendFile.builder().path(path).lines(lines).build();
} }
public static Statement appendFile(String path, Iterable<String> lines, String marker) { public static Statement appendFile(String path, Iterable<String> lines, String delimeter) {
return new AppendFile(path, lines, marker); return AppendFile.builder().path(path).lines(lines).delimeter(delimeter).build();
} }
public static Statement createOrOverwriteFile(String path, Iterable<String> lines) { public static Statement createOrOverwriteFile(String path, Iterable<String> lines) {
return new CreateOrOverwriteFile(path, lines); return CreateOrOverwriteFile.builder().path(path).lines(lines).build();
} }
public static Statement createOrOverwriteFile(String path, Iterable<String> lines, String marker) { public static Statement createOrOverwriteFile(String path, Iterable<String> lines, String delimeter) {
return new CreateOrOverwriteFile(path, lines, marker); return CreateOrOverwriteFile.builder().path(path).lines(lines).delimeter(delimeter).build();
} }
public static CreateRunScript createRunScript(String instanceName, Iterable<String> exports, String pwd, public static CreateRunScript createRunScript(String instanceName, Iterable<String> exports, String pwd,
Iterable<Statement> statements) {// TODO: convert so Iterable<Statement> statements) {// TODO: convert so
// that // that
// createRunScript // createRunScript
// can take from a // can take from a
@ -101,7 +106,8 @@ public class Statements {
/** /**
* *
* Runs the script in a way that it can be matched later with {@link #findPid} * Runs the script in a way that it can be matched later with
* {@link #findPid}
* *
* @param instanceName * @param instanceName
* - what to match the process on * - what to match the process on
@ -119,7 +125,8 @@ public class Statements {
} }
/** /**
* Kills the pid and subprocesses related to the variable {@code FOUND_PID} if set. * Kills the pid and subprocesses related to the variable {@code FOUND_PID}
* if set.
* *
* @see #findPid * @see #findPid
*/ */
@ -128,7 +135,8 @@ public class Statements {
} }
/** /**
* statement can have multiple newlines, note you should use {@code lf} to be portable * statement can have multiple newlines, note you should use {@code lf} to be
* portable
* *
* @see ShellToken * @see ShellToken
*/ */
@ -155,12 +163,12 @@ public class Statements {
* @param directory * @param directory
*/ */
public static Statement extractTargzIntoDirectory(String method, URI endpoint, Multimap<String, String> headers, public static Statement extractTargzIntoDirectory(String method, URI endpoint, Multimap<String, String> headers,
String directory) { String directory) {
return new PipeHttpResponseToTarxpzfIntoDirectory(method, endpoint, headers, directory); return new PipeHttpResponseToTarxpzfIntoDirectory(method, endpoint, headers, directory);
} }
public static Statement extractTargzIntoDirectory(URI targz, String directory) { public static Statement extractTargzIntoDirectory(URI targz, String directory) {
return extractTargzIntoDirectory("GET", targz, ImmutableMultimap.<String, String>of(), directory); return extractTargzIntoDirectory("GET", targz, ImmutableMultimap.<String, String> of(), directory);
} }
/** /**
@ -175,7 +183,7 @@ public class Statements {
* @param directory * @param directory
*/ */
public static Statement extractZipIntoDirectory(String method, URI endpoint, Multimap<String, String> headers, public static Statement extractZipIntoDirectory(String method, URI endpoint, Multimap<String, String> headers,
String directory) { String directory) {
return new UnzipHttpResponseIntoDirectory(method, endpoint, headers, directory); return new UnzipHttpResponseIntoDirectory(method, endpoint, headers, directory);
} }

View File

@ -94,11 +94,11 @@ public class SwitchArg implements Statement, AcceptsStatementVisitor {
if (shouldIndent) if (shouldIndent)
actionBuilder.append(INDENT); actionBuilder.append(INDENT);
actionBuilder.append(line).append(ShellToken.LF.to(family)); actionBuilder.append(line).append(ShellToken.LF.to(family));
if (line.indexOf(CreateRunScript.MARKER) != -1) { if (line.indexOf(CreateRunScript.DELIMETER) != -1) {
inRunScript = inRunScript ? false : true; inRunScript = inRunScript ? false : true;
} }
if (line.indexOf(AppendFile.MARKER) != -1) { if (line.indexOf(AppendFile.DELIMETER) != -1) {
inCreateFile = inCreateFile ? false : true; inCreateFile = inCreateFile ? false : true;
} }
shouldIndent = !inCreateFile && !inRunScript; shouldIndent = !inCreateFile && !inRunScript;

View File

@ -19,27 +19,30 @@
package org.jclouds.scriptbuilder.statements.login; package org.jclouds.scriptbuilder.statements.login;
import static com.google.common.base.Charsets.UTF_8; import static com.google.common.base.Charsets.UTF_8;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.crypto.Sha512Crypt; import org.jclouds.crypto.Sha512Crypt;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.scriptbuilder.domain.OsFamily; import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.StatementList; import org.jclouds.scriptbuilder.domain.StatementList;
import org.jclouds.scriptbuilder.statements.ssh.SshStatements; import org.jclouds.scriptbuilder.statements.ssh.SshStatements;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Preconditions; import com.google.common.base.Predicates;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.io.Files; import com.google.common.io.Files;
import com.google.inject.ImplementedBy; import com.google.inject.ImplementedBy;
@ -288,7 +291,8 @@ public class AdminAccess implements Statement {
} }
} }
private Config config; @VisibleForTesting
Config config;
protected AdminAccess(Config in) { protected AdminAccess(Config in) {
this.config = checkNotNull(in, "in"); this.config = checkNotNull(in, "in");
@ -344,9 +348,14 @@ public class AdminAccess implements Statement {
checkNotNull(family, "family"); checkNotNull(family, "family");
if (family == OsFamily.WINDOWS) if (family == OsFamily.WINDOWS)
throw new UnsupportedOperationException("windows not yet implemented"); throw new UnsupportedOperationException("windows not yet implemented");
checkArgument(!"root".equals(config.getAdminUsername()), "cannot create admin user 'root'; " +
"ensure jclouds is not running as root, or specify an explicit non-root username in AdminAccess");
if (Iterables.any(
Lists.newArrayList(config.getAdminUsername(), config.getAdminPassword(), config.getAdminPublicKey(),
config.getAdminPrivateKey(), config.getLoginPassword()), Predicates.isNull()))
init(new DefaultConfiguration());
checkNotNull(config.getAdminUsername(), "adminUsername"); checkNotNull(config.getAdminUsername(), "adminUsername");
Preconditions.checkArgument(!"root".equals(config.getAdminUsername()), "cannot create admin user 'root'; " +
"ensure jclouds is not running as root, or specify an explicit non-root username in AdminAccess");
checkNotNull(config.getAdminPassword(), "adminPassword"); checkNotNull(config.getAdminPassword(), "adminPassword");
checkNotNull(config.getAdminPublicKey(), "adminPublicKey"); checkNotNull(config.getAdminPublicKey(), "adminPublicKey");
checkNotNull(config.getAdminPrivateKey(), "adminPrivateKey"); checkNotNull(config.getAdminPrivateKey(), "adminPrivateKey");

View File

@ -19,7 +19,7 @@
package org.jclouds.scriptbuilder.statements.login; package org.jclouds.scriptbuilder.statements.login;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.scriptbuilder.domain.Statements.appendFile; import static org.jclouds.scriptbuilder.domain.Statements.createOrOverwriteFile;
import static org.jclouds.scriptbuilder.domain.Statements.exec; import static org.jclouds.scriptbuilder.domain.Statements.exec;
import org.jclouds.scriptbuilder.domain.OsFamily; import org.jclouds.scriptbuilder.domain.OsFamily;
@ -45,8 +45,7 @@ public class Sudoers implements Statement {
if (family == OsFamily.WINDOWS) if (family == OsFamily.WINDOWS)
throw new UnsupportedOperationException("windows not yet implemented"); throw new UnsupportedOperationException("windows not yet implemented");
Builder<Statement> statements = ImmutableList.<Statement> builder(); Builder<Statement> statements = ImmutableList.<Statement> builder();
statements.add(exec("{rm} " + sudoers)); statements.add(createOrOverwriteFile(sudoers, ImmutableSet.of("root ALL = (ALL) ALL", "%wheel ALL = (ALL) NOPASSWD:ALL")));
statements.add(appendFile(sudoers, ImmutableSet.of("root ALL = (ALL) ALL", "%wheel ALL = (ALL) NOPASSWD:ALL")));
statements.add(exec("chmod 0440 " + sudoers)); statements.add(exec("chmod 0440 " + sudoers));
return new StatementList(statements.build()).render(family); return new StatementList(statements.build()).render(family);
} }

View File

@ -49,7 +49,7 @@ public class SshdConfig implements Statement {
Statement prependSshdConfig = exec(String.format( Statement prependSshdConfig = exec(String.format(
"exec 3<> %1$s && awk -v TEXT=\"%2$s\n\" 'BEGIN {print TEXT}{print}' %1$s >&3", sshdConfig, "exec 3<> %1$s && awk -v TEXT=\"%2$s\n\" 'BEGIN {print TEXT}{print}' %1$s >&3", sshdConfig,
linesToPrepend)); linesToPrepend));
Statement reloadSshdConfig = exec("/etc/init.d/sshd reload||/etc/init.d/ssh reload"); Statement reloadSshdConfig = exec("hash service 2>/dev/null && service ssh reload || /etc/init.d/ssh* reload");
return newStatementList(prependSshdConfig, reloadSshdConfig).render(family); return newStatementList(prependSshdConfig, reloadSshdConfig).render(family);
} }

View File

@ -49,12 +49,9 @@ public class InitBuilderTest {
appendFile("{tmp}{fs}{uid}{fs}scripttest{fs}temp.txt", ImmutableList.<String> of("hello world")), appendFile("{tmp}{fs}{uid}{fs}scripttest{fs}temp.txt", ImmutableList.<String> of("hello world")),
exec("find /"))); exec("find /")));
@Test @Test(expectedExceptions = UnsupportedOperationException.class)
public void testBuildSimpleWindows() throws MalformedURLException, IOException { public void testBuildSimpleWindows() throws MalformedURLException, IOException {
assertEquals( testInitBuilder.render(OsFamily.WINDOWS);
testInitBuilder.render(OsFamily.WINDOWS),
CharStreams.toString(Resources.newReaderSupplier(
Resources.getResource("test_init." + ShellToken.SH.to(OsFamily.WINDOWS)), Charsets.UTF_8)));
} }
@Test @Test

View File

@ -0,0 +1,105 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you 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;
import static org.jclouds.scriptbuilder.domain.Statements.appendFile;
import static org.jclouds.scriptbuilder.domain.Statements.call;
import static org.jclouds.scriptbuilder.domain.Statements.exec;
import static org.jclouds.scriptbuilder.domain.Statements.interpret;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.net.MalformedURLException;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.ShellToken;
import org.testng.annotations.Test;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.CharStreams;
import com.google.common.io.Resources;
/**
* Tests possible uses of InitScript
*
* @author Adrian Cole
*/
public class InitScriptTest {
InitScript testInitScript = InitScript
.builder()
.name("mkebsboot")
.home("/mnt/tmp")
.exportVariables(ImmutableMap.of("tmpDir", "/mnt/tmp"))
.run(appendFile("{tmp}{fs}{uid}{fs}scripttest{fs}temp.txt", ImmutableList.<String> of("hello world")),
exec("find /")).build();
public void testBuildSimpleWindows() throws MalformedURLException, IOException {
assertEquals(
testInitScript.render(OsFamily.WINDOWS),
CharStreams.toString(Resources.newReaderSupplier(
Resources.getResource("test_init." + ShellToken.SH.to(OsFamily.WINDOWS)), Charsets.UTF_8)));
}
public void testBuildSimpleUNIX() throws MalformedURLException, IOException {
assertEquals(
testInitScript.render(OsFamily.UNIX),
CharStreams.toString(Resources.newReaderSupplier(
Resources.getResource("test_init." + ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8)));
}
public void testBuildEBS() throws MalformedURLException, IOException {
assertEquals(InitScript
.builder()
.name("mkebsboot")
.home("tmp")
.logDir("/tmp/logs")
.exportVariables(ImmutableMap.of("imageDir", "/mnt/tmp", "ebsDevice", "/dev/sdh", "ebsMountPoint", "/mnt/ebs"))
.run(interpret(
"echo creating a filesystem and mounting the ebs volume",
"{md} {varl}IMAGE_DIR{varr} {varl}EBS_MOUNT_POINT{varr}",
"rm -rf {varl}IMAGE_DIR{varr}/*",
"yes| mkfs -t ext3 {varl}EBS_DEVICE{varr} 2>&-",
"mount {varl}EBS_DEVICE{varr} {varl}EBS_MOUNT_POINT{varr}",
"echo making a local working copy of the boot disk",
"rsync -ax --exclude /ubuntu/.bash_history --exclude /home/*/.bash_history --exclude /etc/ssh/ssh_host_* --exclude /etc/ssh/moduli --exclude /etc/udev/rules.d/*persistent-net.rules --exclude /var/lib/ec2/* --exclude=/mnt/* --exclude=/proc/* --exclude=/tmp/* --exclude=/dev/log / {varl}IMAGE_DIR{varr}",
"echo preparing the local working copy",
"touch {varl}IMAGE_DIR{varr}/etc/init.d/ec2-init-user-data",
"echo copying the local working copy to the ebs mount", "{cd} {varl}IMAGE_DIR{varr}",
"tar -cSf - * | tar xf - -C {varl}EBS_MOUNT_POINT{varr}", "echo size of ebs",
"du -sk {varl}EBS_MOUNT_POINT{varr}", "echo size of source",
"du -sk {varl}IMAGE_DIR{varr}", "rm -rf {varl}IMAGE_DIR{varr}/*",
"umount {varl}EBS_MOUNT_POINT{varr}", "echo ----COMPLETE----")).build().render(OsFamily.UNIX),
CharStreams.toString(Resources.newReaderSupplier(
Resources.getResource("test_ebs." + ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8)));
}
InitScript testCallInRun = InitScript.builder().name("testcall").init(exec("echo hello"))
.run(call("sourceEnvFile", "foo"), exec("find /")).build();
@Test
public void testCallInRunUNIX() throws MalformedURLException, IOException {
assertEquals(
testCallInRun.render(OsFamily.UNIX),
CharStreams.toString(Resources.newReaderSupplier(
Resources.getResource("test_init_script." + ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8)));
}
}

View File

@ -53,16 +53,9 @@ public class CreateRunScriptTest {
.getResource("test_runrun." + ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8))); .getResource("test_runrun." + ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8)));
} }
public void testWINDOWS() throws IOException { @Test(expectedExceptions = UnsupportedOperationException.class)
assertEquals(statement.render(OsFamily.WINDOWS), CharStreams.toString(Resources.newReaderSupplier(Resources public void testWINDOWSUnimplemented() throws IOException {
.getResource("test_runrun." + ShellToken.SH.to(OsFamily.WINDOWS)), Charsets.UTF_8))); statement.render(OsFamily.WINDOWS);
}
public void testRedirectGuard() {
assertEquals(CreateRunScript.addSpaceToEnsureWeDontAccidentallyRedirectFd("foo>>"), "foo>>");
assertEquals(CreateRunScript.addSpaceToEnsureWeDontAccidentallyRedirectFd("foo0>>"), "foo0 >>");
assertEquals(CreateRunScript.addSpaceToEnsureWeDontAccidentallyRedirectFd("foo1>>"), "foo1 >>");
assertEquals(CreateRunScript.addSpaceToEnsureWeDontAccidentallyRedirectFd("foo2>>"), "foo2 >>");
} }
} }

View File

@ -40,9 +40,9 @@ public class ShellTokenTest {
"args", "$@").put("varl", "$").put("return", "return").put("exit", "exit").put( "args", "$@").put("varl", "$").put("return", "return").put("exit", "exit").put(
"varr", "").put("libraryPathVariable", "LD_LIBRARY_PATH").put("beginScript", "varr", "").put("libraryPathVariable", "LD_LIBRARY_PATH").put("beginScript",
"#!/bin/bash\nset +u\nshopt -s xpg_echo\nshopt -s expand_aliases\n").put( "#!/bin/bash\nset +u\nshopt -s xpg_echo\nshopt -s expand_aliases\n").put(
"endScript", "exit 0\n").put("vq", "\"").put("beginFunctions", "").put( "endScript", "exit $?\n").put("vq", "\"").put("beginFunctions", "").put(
"endFunctions", "").put("fncl", "function ").put("fncr", " {\n").put("fnce", "endFunctions", "").put("fncl", "function ").put("fncr", " {\n").put("fnce",
" return 0\n}\n").put("export", "export").put("rm", "rm").put("cd", "cd").put( " return $?\n}\n").put("export", "export").put("rm", "rm").put("cd", "cd").put(
"tmp", "/tmp").put("uid", "$USER").put("root", "/").put("closeFd", ">&-").put("md", "tmp", "/tmp").put("uid", "$USER").put("root", "/").put("closeFd", ">&-").put("md",
"mkdir -p").put("escvar", "\\").build(); "mkdir -p").put("escvar", "\\").build();
assertEquals(ShellToken.tokenValueMap(OsFamily.UNIX), expected); assertEquals(ShellToken.tokenValueMap(OsFamily.UNIX), expected);

View File

@ -39,7 +39,17 @@ public class SwitchArgTest {
assertEquals(new SwitchArg(1, ImmutableMap.of("0", newStatementList(appendFile( assertEquals(new SwitchArg(1, ImmutableMap.of("0", newStatementList(appendFile(
"{tmp}{fs}{uid}{fs}scripttest{fs}temp.txt", Collections.singleton("hello world")), "{tmp}{fs}{uid}{fs}scripttest{fs}temp.txt", Collections.singleton("hello world")),
interpret("echo hello zero{lf}")), "1", interpret("echo hello one{lf}"))).render(OsFamily.UNIX), interpret("echo hello zero{lf}")), "1", interpret("echo hello one{lf}"))).render(OsFamily.UNIX),
"case $1 in\n0)\n cat >> /tmp/$USER/scripttest/temp.txt <<'END_OF_FILE'\nhello world\nEND_OF_FILE\n echo hello zero\n ;;\n1)\n echo hello one\n ;;\nesac\n"); "case $1 in\n"+
"0)\n"+
" cat >> /tmp/$USER/scripttest/temp.txt <<-'END_OF_JCLOUDS_FILE'\n"+
"\thello world\n"+
"END_OF_JCLOUDS_FILE\n"+
" echo hello zero\n"+
" ;;\n"+
"1)\n"+
" echo hello one\n"+
" ;;\n"+
"esac\n");
} }
public void testSwitchArgWindows() { public void testSwitchArgWindows() {

View File

@ -18,20 +18,19 @@
*/ */
package org.jclouds.scriptbuilder.functions; package org.jclouds.scriptbuilder.functions;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expect;
import static org.easymock.classextension.EasyMock.createMock; import static org.easymock.EasyMock.replay;
import static org.easymock.classextension.EasyMock.replay; import static org.easymock.EasyMock.verify;
import static org.easymock.classextension.EasyMock.verify;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.scriptbuilder.InitBuilder; import org.jclouds.scriptbuilder.InitScript;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.Statements; import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.scriptbuilder.statements.login.AdminAccess; import org.jclouds.scriptbuilder.statements.login.AdminAccess;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
/** /**
@ -97,8 +96,8 @@ public class CredentialsFromAdminAccessTest {
replay(statement); replay(statement);
replay(creds); replay(creds);
InitBuilder testInitBuilder = new InitBuilder("mkebsboot", "/mnt/tmp", "/mnt/tmp", ImmutableMap.of("tmpDir", InitScript testInitBuilder = InitScript.builder().name("mkebsboot").home("/mnt/tmp")
"/mnt/tmp"), ImmutableList.<Statement> of(statement)); .exportVariables(ImmutableMap.of("tmpDir", "/mnt/tmp")).run(statement).build();
assertEquals(CredentialsFromAdminAccess.INSTANCE.apply(testInitBuilder), creds); assertEquals(CredentialsFromAdminAccess.INSTANCE.apply(testInitBuilder), creds);

View File

@ -18,18 +18,16 @@
*/ */
package org.jclouds.scriptbuilder.functions; package org.jclouds.scriptbuilder.functions;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expect;
import static org.easymock.classextension.EasyMock.createMock; import static org.easymock.EasyMock.replay;
import static org.easymock.classextension.EasyMock.replay; import static org.easymock.EasyMock.verify;
import static org.easymock.classextension.EasyMock.verify;
import org.jclouds.scriptbuilder.InitBuilder; import org.jclouds.scriptbuilder.InitScript;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.Statements; import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.scriptbuilder.statements.login.AdminAccess; import org.jclouds.scriptbuilder.statements.login.AdminAccess;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
/** /**
@ -101,8 +99,8 @@ public class InitAdminAccessTest {
replay(statement); replay(statement);
replay(newStatement); replay(newStatement);
InitBuilder testInitBuilder = new InitBuilder("mkebsboot", "/mnt/tmp", "/mnt/tmp", ImmutableMap.of("tmpDir", InitScript testInitBuilder = InitScript.builder().name("mkebsboot").home("/mnt/tmp")
"/mnt/tmp"), ImmutableList.<Statement> of(statement)); .exportVariables(ImmutableMap.of("tmpDir", "/mnt/tmp")).run(statement).build();
InitAdminAccess initAdminAccess = new InitAdminAccess(configuration); InitAdminAccess initAdminAccess = new InitAdminAccess(configuration);

View File

@ -23,14 +23,13 @@ import static org.testng.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import org.jclouds.scriptbuilder.InitBuilder; import org.jclouds.scriptbuilder.InitScript;
import org.jclouds.scriptbuilder.domain.OsFamily; import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.ShellToken; import org.jclouds.scriptbuilder.domain.ShellToken;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.CharStreams; import com.google.common.io.CharStreams;
import com.google.common.io.Resources; import com.google.common.io.Resources;
@ -48,11 +47,10 @@ public class InstallJDKTest {
} }
public void testInstallJDKUNIXInScriptBuilderSourcesSetupPublicCurl() throws IOException { public void testInstallJDKUNIXInScriptBuilderSourcesSetupPublicCurl() throws IOException {
assertEquals( assertEquals(InitScript.builder().name("install_jdk").run(InstallJDK.fromURL()).build().render(OsFamily.UNIX),
new InitBuilder("install_jdk", ImmutableSet.<Statement> of(), ImmutableSet.<Statement> of(InstallJDK
.fromURL())).render(OsFamily.UNIX),
CharStreams.toString(Resources.newReaderSupplier( CharStreams.toString(Resources.newReaderSupplier(
Resources.getResource("test_install_jdk_scriptbuilder." + ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8))); Resources.getResource("test_install_jdk_scriptbuilder." + ShellToken.SH.to(OsFamily.UNIX)),
Charsets.UTF_8)));
} }
public void testInstallJDKUNIXWithURL() throws IOException { public void testInstallJDKUNIXWithURL() throws IOException {

View File

@ -19,6 +19,7 @@
package org.jclouds.scriptbuilder.statements.login; package org.jclouds.scriptbuilder.statements.login;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import java.io.IOException; import java.io.IOException;
@ -77,8 +78,8 @@ public class AdminAccessTest {
AdminAccess.standard().init(TestConfiguration.INSTANCE).render(OsFamily.WINDOWS); AdminAccess.standard().init(TestConfiguration.INSTANCE).render(OsFamily.WINDOWS);
} }
@Test(expectedExceptions=IllegalArgumentException.class) @Test(expectedExceptions = IllegalArgumentException.class)
//for issue 682 // for issue 682
public void testRootNotAllowed() throws IOException { public void testRootNotAllowed() throws IOException {
TestConfiguration.INSTANCE.reset(); TestConfiguration.INSTANCE.reset();
try { try {
@ -88,4 +89,34 @@ public class AdminAccessTest {
} }
} }
@Test(expectedExceptions = NullPointerException.class)
public void testFamilyRequiredAllowed() throws IOException {
AdminAccess.standard().render(null);
}
public void testWhenUninitializedLazyInitWithDefaultConfiguration() throws IOException {
AdminAccess access = AdminAccess.standard();
// before rendered, holder is empty
assertEquals(access.config.getAdminUsername(), null);
assertEquals(access.config.getAdminPassword(), null);
assertEquals(access.config.getAdminPublicKey(), null);
assertEquals(access.config.getAdminPrivateKey(), null);
assertEquals(access.config.getLoginPassword(), null);
access.render(OsFamily.UNIX);
// DefaultConfiguration
try {
assertEquals(access.config.getAdminUsername(), System.getProperty("user.name"));
assertNotNull(access.config.getAdminPassword());
assertNotNull(access.config.getAdminPublicKey());
assertNotNull(access.config.getAdminPrivateKey());
assertNotNull(access.config.getLoginPassword());
} catch (AssertionError e) {
throw e;
} catch (Throwable e) {
// we are catching throwables here, in case the test runner doesn't
// have ssh keys setup
}
}
} }

View File

@ -32,7 +32,11 @@ public class SudoStatementsTest {
public void testCreateWheelUNIX() { public void testCreateWheelUNIX() {
assertEquals( assertEquals(
SudoStatements.createWheel().render(OsFamily.UNIX), SudoStatements.createWheel().render(OsFamily.UNIX),
"rm /etc/sudoers\ncat >> /etc/sudoers <<'END_OF_FILE'\nroot ALL = (ALL) ALL\n%wheel ALL = (ALL) NOPASSWD:ALL\nEND_OF_FILE\nchmod 0440 /etc/sudoers\n"); "cat > /etc/sudoers <<-'END_OF_JCLOUDS_FILE'\n"+
"\troot ALL = (ALL) ALL\n"+
"\t%wheel ALL = (ALL) NOPASSWD:ALL\n"+
"END_OF_JCLOUDS_FILE\n"+
"chmod 0440 /etc/sudoers\n");
} }
@Test(expectedExceptions = UnsupportedOperationException.class) @Test(expectedExceptions = UnsupportedOperationException.class)

View File

@ -61,13 +61,13 @@ public class UserAddTest {
public void testWithSshAuthorizedKeyUNIX() { public void testWithSshAuthorizedKeyUNIX() {
assertEquals( assertEquals(
UserAdd.builder().login("me").authorizeRSAPublicKey("rsapublickey").build().render(OsFamily.UNIX), UserAdd.builder().login("me").authorizeRSAPublicKey("rsapublickey").build().render(OsFamily.UNIX),
"mkdir -p /home/users\nuseradd -s /bin/bash -m -d /home/users/me me\nmkdir -p /home/users/me/.ssh\ncat >> /home/users/me/.ssh/authorized_keys <<'END_OF_FILE'\nrsapublickey\nEND_OF_FILE\nchmod 600 /home/users/me/.ssh/authorized_keys\nchown -R me /home/users/me\n"); "mkdir -p /home/users\nuseradd -s /bin/bash -m -d /home/users/me me\nmkdir -p /home/users/me/.ssh\ncat >> /home/users/me/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'\n\trsapublickey\nEND_OF_JCLOUDS_FILE\nchmod 600 /home/users/me/.ssh/authorized_keys\nchown -R me /home/users/me\n");
} }
public void testWithSshInstalledKeyUNIX() { public void testWithSshInstalledKeyUNIX() {
assertEquals( assertEquals(
UserAdd.builder().login("me").installRSAPrivateKey("rsaprivate").build().render(OsFamily.UNIX), UserAdd.builder().login("me").installRSAPrivateKey("rsaprivate").build().render(OsFamily.UNIX),
"mkdir -p /home/users\nuseradd -s /bin/bash -m -d /home/users/me me\nmkdir -p /home/users/me/.ssh\nrm /home/users/me/.ssh/id_rsa\ncat >> /home/users/me/.ssh/id_rsa <<'END_OF_FILE'\nrsaprivate\nEND_OF_FILE\nchmod 600 /home/users/me/.ssh/id_rsa\nchown -R me /home/users/me\n"); "mkdir -p /home/users\nuseradd -s /bin/bash -m -d /home/users/me me\nmkdir -p /home/users/me/.ssh\nrm /home/users/me/.ssh/id_rsa\ncat >> /home/users/me/.ssh/id_rsa <<-'END_OF_JCLOUDS_FILE'\n\trsaprivate\nEND_OF_JCLOUDS_FILE\nchmod 600 /home/users/me/.ssh/id_rsa\nchown -R me /home/users/me\n");
} }
@Test(expectedExceptions = UnsupportedOperationException.class) @Test(expectedExceptions = UnsupportedOperationException.class)

View File

@ -34,26 +34,46 @@ public class AuthorizeRSAPublicKeyTest {
public void testAuthorizeRSAPublicKeyUNIXCurrentUser() { public void testAuthorizeRSAPublicKeyUNIXCurrentUser() {
assertEquals( assertEquals(
new AuthorizeRSAPublicKeys(ImmutableSet.of("ssh-dss AAAAB")).render(OsFamily.UNIX), new AuthorizeRSAPublicKeys(ImmutableSet.of("ssh-dss AAAAB")).render(OsFamily.UNIX),
"mkdir -p ~/.ssh\ncat >> ~/.ssh/authorized_keys <<'END_OF_FILE'\nssh-dss AAAAB\nEND_OF_FILE\nchmod 600 ~/.ssh/authorized_keys\n"); "mkdir -p ~/.ssh\n"+
"cat >> ~/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'\n"+
"\tssh-dss AAAAB\n"+
"END_OF_JCLOUDS_FILE\n"+
"chmod 600 ~/.ssh/authorized_keys\n");
} }
public void testAuthorizeRSAPublicKeyUNIXCurrentUserWith2Keys() { public void testAuthorizeRSAPublicKeyUNIXCurrentUserWith2Keys() {
assertEquals( assertEquals(
new AuthorizeRSAPublicKeys(ImmutableSet.of("ssh-dss AAAAB", "ssh-dss CCCCD")).render(OsFamily.UNIX), new AuthorizeRSAPublicKeys(ImmutableSet.of("ssh-dss AAAAB", "ssh-dss CCCCD")).render(OsFamily.UNIX),
"mkdir -p ~/.ssh\ncat >> ~/.ssh/authorized_keys <<'END_OF_FILE'\nssh-dss AAAAB\n\nssh-dss CCCCD\nEND_OF_FILE\nchmod 600 ~/.ssh/authorized_keys\n"); "mkdir -p ~/.ssh\n"+
"cat >> ~/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'\n"+
"\tssh-dss AAAAB\n"+
"\t\n"+
"\tssh-dss CCCCD\n"+
"END_OF_JCLOUDS_FILE\n"+
"chmod 600 ~/.ssh/authorized_keys\n");
} }
public void testAuthorizeRSAPublicKeyUNIXSpecifiedDir() { public void testAuthorizeRSAPublicKeyUNIXSpecifiedDir() {
assertEquals( assertEquals(
new AuthorizeRSAPublicKeys("/home/me/.ssh", ImmutableSet.of("ssh-dss AAAAB")).render(OsFamily.UNIX), new AuthorizeRSAPublicKeys("/home/me/.ssh", ImmutableSet.of("ssh-dss AAAAB")).render(OsFamily.UNIX),
"mkdir -p /home/me/.ssh\ncat >> /home/me/.ssh/authorized_keys <<'END_OF_FILE'\nssh-dss AAAAB\nEND_OF_FILE\nchmod 600 /home/me/.ssh/authorized_keys\n"); "mkdir -p /home/me/.ssh\n"+
"cat >> /home/me/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'\n"+
"\tssh-dss AAAAB\n"+
"END_OF_JCLOUDS_FILE\n"+
"chmod 600 /home/me/.ssh/authorized_keys\n");
} }
public void testAuthorizeRSAPublicKeyUNIXSpecifiedDirWith2Keys() { public void testAuthorizeRSAPublicKeyUNIXSpecifiedDirWith2Keys() {
assertEquals( assertEquals(
new AuthorizeRSAPublicKeys("/home/me/.ssh", ImmutableSet.of("ssh-dss AAAAB", "ssh-dss CCCCD")) new AuthorizeRSAPublicKeys("/home/me/.ssh", ImmutableSet.of("ssh-dss AAAAB", "ssh-dss CCCCD"))
.render(OsFamily.UNIX), .render(OsFamily.UNIX),
"mkdir -p /home/me/.ssh\ncat >> /home/me/.ssh/authorized_keys <<'END_OF_FILE'\nssh-dss AAAAB\n\nssh-dss CCCCD\nEND_OF_FILE\nchmod 600 /home/me/.ssh/authorized_keys\n"); "mkdir -p /home/me/.ssh\n"+
"cat >> /home/me/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'\n"+
"\tssh-dss AAAAB\n"+
"\t\n"+
"\tssh-dss CCCCD\n"+
"END_OF_JCLOUDS_FILE\n"+
"chmod 600 /home/me/.ssh/authorized_keys\n");
} }
@Test(expectedExceptions = UnsupportedOperationException.class) @Test(expectedExceptions = UnsupportedOperationException.class)

View File

@ -33,15 +33,28 @@ public class InstallRSAPrivateKeyTest {
assertEquals( assertEquals(
new InstallRSAPrivateKey("-----BEGIN RSA PRIVATE KEY-----\n-----END RSA PRIVATE KEY-----\n") new InstallRSAPrivateKey("-----BEGIN RSA PRIVATE KEY-----\n-----END RSA PRIVATE KEY-----\n")
.render(OsFamily.UNIX), .render(OsFamily.UNIX),
"mkdir -p ~/.ssh\nrm ~/.ssh/id_rsa\ncat >> ~/.ssh/id_rsa <<'END_OF_FILE'\n-----BEGIN RSA PRIVATE KEY-----\n-----END RSA PRIVATE KEY-----\n\nEND_OF_FILE\nchmod 600 ~/.ssh/id_rsa\n"); "mkdir -p ~/.ssh\n"+
"rm ~/.ssh/id_rsa\n"+
"cat >> ~/.ssh/id_rsa <<-'END_OF_JCLOUDS_FILE'\n"+
"\t-----BEGIN RSA PRIVATE KEY-----\n"+
"\t-----END RSA PRIVATE KEY-----\n"+
"\t\n"+
"END_OF_JCLOUDS_FILE\n"+
"chmod 600 ~/.ssh/id_rsa\n");
} }
public void testInstallRSAPrivateKeyUNIXSpecifiedHome() { public void testInstallRSAPrivateKeyUNIXSpecifiedHome() {
assertEquals( assertEquals(
new InstallRSAPrivateKey("/home/me/.ssh", "-----BEGIN RSA PRIVATE KEY-----\n-----END RSA PRIVATE KEY-----\n") new InstallRSAPrivateKey("/home/me/.ssh", "-----BEGIN RSA PRIVATE KEY-----\n-----END RSA PRIVATE KEY-----\n")
.render(OsFamily.UNIX), .render(OsFamily.UNIX),
"mkdir -p /home/me/.ssh\nrm /home/me/.ssh/id_rsa\ncat >> /home/me/.ssh/id_rsa <<'END_OF_FILE'\n-----BEGIN RSA PRIVATE KEY-----\n-----END RSA PRIVATE KEY-----\n\nEND_OF_FILE\nchmod 600 /home/me/.ssh/id_rsa\n"); "mkdir -p /home/me/.ssh\n"+
} "rm /home/me/.ssh/id_rsa\n"+
"cat >> /home/me/.ssh/id_rsa <<-'END_OF_JCLOUDS_FILE'\n"+
"\t-----BEGIN RSA PRIVATE KEY-----\n"+
"\t-----END RSA PRIVATE KEY-----\n"+
"\t\n"+
"END_OF_JCLOUDS_FILE\n"+
"chmod 600 /home/me/.ssh/id_rsa\n"); }
@Test(expectedExceptions = UnsupportedOperationException.class) @Test(expectedExceptions = UnsupportedOperationException.class)
public void testInstallRSAPrivateKeyWINDOWS() { public void testInstallRSAPrivateKeyWINDOWS() {

View File

@ -38,7 +38,7 @@ public class SshStatementsTest {
.append("PasswordAuthentication no").append("\n")// .append("PasswordAuthentication no").append("\n")//
.append("PermitRootLogin no").append("\n")// .append("PermitRootLogin no").append("\n")//
.append("\" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3").append("\n")// .append("\" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3").append("\n")//
.append("/etc/init.d/sshd reload||/etc/init.d/ssh reload").append("\n").toString()); .append("hash service 2>/dev/null && service ssh reload || /etc/init.d/ssh* reload").append("\n").toString());
} }
public void testSshdConfigUNIX() { public void testSshdConfigUNIX() {
@ -46,7 +46,7 @@ public class SshStatementsTest {
new StringBuilder().append("exec 3<> /etc/ssh/sshd_config && awk -v TEXT=\"")// new StringBuilder().append("exec 3<> /etc/ssh/sshd_config && awk -v TEXT=\"")//
.append("AddressFamily inet6").append("\n")// .append("AddressFamily inet6").append("\n")//
.append("\" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3").append("\n")// .append("\" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3").append("\n")//
.append("/etc/init.d/sshd reload||/etc/init.d/ssh reload").append("\n").toString()); .append("hash service 2>/dev/null && service ssh reload || /etc/init.d/ssh* reload").append("\n").toString());
} }
} }

View File

@ -1,5 +1,5 @@
cat >> /etc/chef/client.rb <<'END_OF_FILE' cat >> /etc/chef/client.rb <<-'END_OF_JCLOUDS_FILE'
log_level :info log_level :info
log_location STDOUT log_location STDOUT
chef_server_url "http://localhost:4000" chef_server_url "http://localhost:4000"
END_OF_FILE END_OF_JCLOUDS_FILE

View File

@ -1,5 +1,5 @@
cat > /etc/chef/client.rb <<'END_OF_FILE' cat > /etc/chef/client.rb <<-'END_OF_JCLOUDS_FILE'
log_level :info log_level :info
log_location STDOUT log_location STDOUT
chef_server_url "http://localhost:4000" chef_server_url "http://localhost:4000"
END_OF_FILE END_OF_JCLOUDS_FILE

View File

@ -16,6 +16,6 @@ chown -R defaultAdminUsername /home/users/defaultAdminUsername
exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
PermitRootLogin no PermitRootLogin no
" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3 " 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3
/etc/init.d/sshd reload||/etc/init.d/ssh reload hash service 2>/dev/null && service ssh reload || /etc/init.d/ssh* reload
awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(1)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}} awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(1)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}}
test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow

View File

@ -1,21 +1,20 @@
rm /etc/sudoers cat > /etc/sudoers <<-'END_OF_JCLOUDS_FILE'
cat >> /etc/sudoers <<'END_OF_FILE' root ALL = (ALL) ALL
root ALL = (ALL) ALL %wheel ALL = (ALL) NOPASSWD:ALL
%wheel ALL = (ALL) NOPASSWD:ALL END_OF_JCLOUDS_FILE
END_OF_FILE
chmod 0440 /etc/sudoers chmod 0440 /etc/sudoers
mkdir -p /home/users mkdir -p /home/users
groupadd -f wheel groupadd -f wheel
useradd -s /bin/bash -g wheel -m -d /home/users/foo -p 'crypt(bar)' foo useradd -s /bin/bash -g wheel -m -d /home/users/foo -p 'crypt(bar)' foo
mkdir -p /home/users/foo/.ssh mkdir -p /home/users/foo/.ssh
cat >> /home/users/foo/.ssh/authorized_keys <<'END_OF_FILE' cat >> /home/users/foo/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'
fooPublicKey fooPublicKey
END_OF_FILE END_OF_JCLOUDS_FILE
chmod 600 /home/users/foo/.ssh/authorized_keys chmod 600 /home/users/foo/.ssh/authorized_keys
chown -R foo /home/users/foo chown -R foo /home/users/foo
exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
PermitRootLogin no PermitRootLogin no
" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3 " 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3
/etc/init.d/sshd reload||/etc/init.d/ssh reload hash service 2>/dev/null && service ssh reload || /etc/init.d/ssh* reload
awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(0)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}} awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(0)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}}
test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow

View File

@ -1,14 +1,14 @@
mkdir -p /home/users mkdir -p /home/users
useradd -s /bin/bash -m -d /home/users/defaultAdminUsername -p 'crypt(0)' defaultAdminUsername useradd -s /bin/bash -m -d /home/users/defaultAdminUsername -p 'crypt(0)' defaultAdminUsername
mkdir -p /home/users/defaultAdminUsername/.ssh mkdir -p /home/users/defaultAdminUsername/.ssh
cat >> /home/users/defaultAdminUsername/.ssh/authorized_keys <<'END_OF_FILE' cat >> /home/users/defaultAdminUsername/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'
publicKey publicKey
END_OF_FILE END_OF_JCLOUDS_FILE
chmod 600 /home/users/defaultAdminUsername/.ssh/authorized_keys chmod 600 /home/users/defaultAdminUsername/.ssh/authorized_keys
mkdir -p /home/users/defaultAdminUsername/.ssh mkdir -p /home/users/defaultAdminUsername/.ssh
rm /home/users/defaultAdminUsername/.ssh/id_rsa rm /home/users/defaultAdminUsername/.ssh/id_rsa
cat >> /home/users/defaultAdminUsername/.ssh/id_rsa <<'END_OF_FILE' cat >> /home/users/defaultAdminUsername/.ssh/id_rsa <<-'END_OF_JCLOUDS_FILE'
privateKey privateKey
END_OF_FILE END_OF_JCLOUDS_FILE
chmod 600 /home/users/defaultAdminUsername/.ssh/id_rsa chmod 600 /home/users/defaultAdminUsername/.ssh/id_rsa
chown -R defaultAdminUsername /home/users/defaultAdminUsername chown -R defaultAdminUsername /home/users/defaultAdminUsername

View File

@ -1,21 +1,20 @@
rm /etc/sudoers cat > /etc/sudoers <<-'END_OF_JCLOUDS_FILE'
cat >> /etc/sudoers <<'END_OF_FILE' root ALL = (ALL) ALL
root ALL = (ALL) ALL %wheel ALL = (ALL) NOPASSWD:ALL
%wheel ALL = (ALL) NOPASSWD:ALL END_OF_JCLOUDS_FILE
END_OF_FILE
chmod 0440 /etc/sudoers chmod 0440 /etc/sudoers
mkdir -p /home/users mkdir -p /home/users
groupadd -f wheel groupadd -f wheel
useradd -s /bin/bash -g wheel -m -d /home/users/defaultAdminUsername -p 'crypt(0)' defaultAdminUsername useradd -s /bin/bash -g wheel -m -d /home/users/defaultAdminUsername -p 'crypt(0)' defaultAdminUsername
mkdir -p /home/users/defaultAdminUsername/.ssh mkdir -p /home/users/defaultAdminUsername/.ssh
cat >> /home/users/defaultAdminUsername/.ssh/authorized_keys <<'END_OF_FILE' cat >> /home/users/defaultAdminUsername/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'
publicKey publicKey
END_OF_FILE END_OF_JCLOUDS_FILE
chmod 600 /home/users/defaultAdminUsername/.ssh/authorized_keys chmod 600 /home/users/defaultAdminUsername/.ssh/authorized_keys
chown -R defaultAdminUsername /home/users/defaultAdminUsername chown -R defaultAdminUsername /home/users/defaultAdminUsername
exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
PermitRootLogin no PermitRootLogin no
" 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3 " 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3
/etc/init.d/sshd reload||/etc/init.d/ssh reload hash service 2>/dev/null && service ssh reload || /etc/init.d/ssh* reload
awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(1)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}} awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(1)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}}
test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow

View File

@ -11,13 +11,13 @@ function default {
export INSTANCE_NAME="mkebsboot" export INSTANCE_NAME="mkebsboot"
export INSTANCE_HOME="/tmp" export INSTANCE_HOME="/tmp"
export LOG_DIR="/tmp/logs" export LOG_DIR="/tmp/logs"
return 0 return $?
} }
function mkebsboot { function mkebsboot {
export IMAGE_DIR="/mnt/tmp" export IMAGE_DIR="/mnt/tmp"
export EBS_DEVICE="/dev/sdh" export EBS_DEVICE="/dev/sdh"
export EBS_MOUNT_POINT="/mnt/ebs" export EBS_MOUNT_POINT="/mnt/ebs"
return 0 return $?
} }
function findPid { function findPid {
unset FOUND_PID; unset FOUND_PID;
@ -65,50 +65,55 @@ init)
mkdir -p $INSTANCE_HOME mkdir -p $INSTANCE_HOME
# create runscript header # create runscript header
cat > $INSTANCE_HOME/mkebsboot.sh <<END_OF_SCRIPT cat > $INSTANCE_HOME/mkebsboot.sh <<-'END_OF_JCLOUDS_SCRIPT'
#!/bin/bash #!/bin/bash
set +u set +u
shopt -s xpg_echo shopt -s xpg_echo
shopt -s expand_aliases shopt -s expand_aliases
PROMPT_COMMAND='echo -ne "\033]0;mkebsboot\007"'
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin PROMPT_COMMAND='echo -ne \"\033]0;mkebsboot\007\"'
export INSTANCE_NAME='mkebsboot' export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
export IMAGE_DIR='$IMAGE_DIR'
export EBS_DEVICE='$EBS_DEVICE' export INSTANCE_NAME='mkebsboot'
export EBS_MOUNT_POINT='$EBS_MOUNT_POINT' END_OF_JCLOUDS_SCRIPT
export INSTANCE_NAME='$INSTANCE_NAME' cat >> $INSTANCE_HOME/mkebsboot.sh <<-END_OF_JCLOUDS_SCRIPT
export INSTANCE_HOME='$INSTANCE_HOME' export IMAGE_DIR='$IMAGE_DIR'
export LOG_DIR='$LOG_DIR' export EBS_DEVICE='$EBS_DEVICE'
END_OF_SCRIPT export EBS_MOUNT_POINT='$EBS_MOUNT_POINT'
export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME'
export LOG_DIR='$LOG_DIR'
END_OF_JCLOUDS_SCRIPT
# add desired commands from the user # add desired commands from the user
cat >> $INSTANCE_HOME/mkebsboot.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/mkebsboot.sh <<-'END_OF_JCLOUDS_SCRIPT'
cd $INSTANCE_HOME cd $INSTANCE_HOME
echo creating a filesystem and mounting the ebs volume echo creating a filesystem and mounting the ebs volume
mkdir -p $IMAGE_DIR $EBS_MOUNT_POINT mkdir -p $IMAGE_DIR $EBS_MOUNT_POINT
rm -rf $IMAGE_DIR/* rm -rf $IMAGE_DIR/*
yes| mkfs -t ext3 $EBS_DEVICE 2>&- yes| mkfs -t ext3 $EBS_DEVICE 2>&-
mount $EBS_DEVICE $EBS_MOUNT_POINT mount $EBS_DEVICE $EBS_MOUNT_POINT
echo making a local working copy of the boot disk echo making a local working copy of the boot disk
rsync -ax --exclude /ubuntu/.bash_history --exclude /home/*/.bash_history --exclude /etc/ssh/ssh_host_* --exclude /etc/ssh/moduli --exclude /etc/udev/rules.d/*persistent-net.rules --exclude /var/lib/ec2/* --exclude=/mnt/* --exclude=/proc/* --exclude=/tmp/* --exclude=/dev/log / $IMAGE_DIR rsync -ax --exclude /ubuntu/.bash_history --exclude /home/*/.bash_history --exclude /etc/ssh/ssh_host_* --exclude /etc/ssh/moduli --exclude /etc/udev/rules.d/*persistent-net.rules --exclude /var/lib/ec2/* --exclude=/mnt/* --exclude=/proc/* --exclude=/tmp/* --exclude=/dev/log / $IMAGE_DIR
echo preparing the local working copy echo preparing the local working copy
touch $IMAGE_DIR/etc/init.d/ec2-init-user-data touch $IMAGE_DIR/etc/init.d/ec2-init-user-data
echo copying the local working copy to the ebs mount echo copying the local working copy to the ebs mount
cd $IMAGE_DIR cd $IMAGE_DIR
tar -cSf - * | tar xf - -C $EBS_MOUNT_POINT tar -cSf - * | tar xf - -C $EBS_MOUNT_POINT
echo size of ebs echo size of ebs
du -sk $EBS_MOUNT_POINT du -sk $EBS_MOUNT_POINT
echo size of source echo size of source
du -sk $IMAGE_DIR du -sk $IMAGE_DIR
rm -rf $IMAGE_DIR/* rm -rf $IMAGE_DIR/*
umount $EBS_MOUNT_POINT umount $EBS_MOUNT_POINT
echo ----COMPLETE---- echo ----COMPLETE----
END_OF_SCRIPT END_OF_JCLOUDS_SCRIPT
# add runscript footer # add runscript footer
cat >> $INSTANCE_HOME/mkebsboot.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/mkebsboot.sh <<-'END_OF_JCLOUDS_SCRIPT'
exit 0 exit $?
END_OF_SCRIPT
END_OF_JCLOUDS_SCRIPT
chmod u+x $INSTANCE_HOME/mkebsboot.sh chmod u+x $INSTANCE_HOME/mkebsboot.sh
;; ;;
@ -142,4 +147,4 @@ run)
$INSTANCE_HOME/$INSTANCE_NAME.sh $INSTANCE_HOME/$INSTANCE_NAME.sh
;; ;;
esac esac
exit 0 exit $?

View File

@ -25,4 +25,4 @@ function findPid {
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
findPid $@ || exit 1 findPid $@ || exit 1
echo $FOUND_PID echo $FOUND_PID
exit 0 exit $?

View File

@ -1,134 +0,0 @@
@echo off
set PATH=
set JAVA_HOME=
set PATH=
GOTO FUNCTION_END
:abort
echo aborting: %EXCEPTION%
exit /b 1
:default
set INSTANCE_NAME=mkebsboot
set INSTANCE_HOME=/mnt/tmp
set LOG_DIR=/mnt/tmp
exit /b 0
:mkebsboot
set TMP_DIR=/mnt/tmp
exit /b 0
:findPid
set FOUND_PID=
set _expression=%1
shift
set FIND_PROCESS=TASKLIST /FI "WINDOWTITLE eq %_expression%" /NH
FOR /F "usebackq tokens=2 delims= " %%A IN (`cmd /c "%FIND_PROCESS% 2>NUL"`) DO (
SET FOUND_PID=%%A
)
if defined FOUND_PID (
exit /b 0
) else (
set EXCEPTION=%_expression% not found
exit /b 1
)
:forget
SETLOCAL
set FOUND_PID=
set NEXT_MINUTE=
set INSTANCE_NAME=%1
shift
set SCRIPT=%1
shift
set LOG_DIR=%1
shift
CALL :findProcess %INSTANCE_NAME%
if defined FOUND_PID (
echo %INSTANCE_NAME% already running pid [%FOUND_PID%]
) else (
CALL :nextMinute
set _DATE=%DATE:~4%
set CMD=schtasks /create /sd %_DATE% /tn %INSTANCE_NAME% /ru System /tr "cmd /c title %INSTANCE_NAME%&%SCRIPT% >%LOG_DIR%\stdout.log 2>%LOG_DIR%\stderr.log" /sc:once /st %NEXT_MINUTE%
echo %INSTANCE_NAME% will start at %NEXT_MINUTE%
set SECONDS=%TIME:~6,2%
set /a SECOND=60-SECONDS
%CMD% >NUL
ping -n %SECONDS% 127.0.0.1 > NUL 2>&1
CALL :findProcess %INSTANCE_NAME%
if not defined FOUND_PID (
set EXCEPTION=%INSTANCE_NAME% did not start
abort
)
)
exit /b 0
:FUNCTION_END
set PATH=c:\windows\;C:\windows\system32;c:\windows\system32\wbem
if not "%1" == "init" if not "%1" == "status" if not "%1" == "stop" if not "%1" == "start" if not "%1" == "tail" if not "%1" == "tailerr" if not "%1" == "run" (
set EXCEPTION=bad argument: %1 not in init status stop start tail tailerr run
goto abort
)
goto CASE_%1
:CASE_init
call :default
if errorlevel 1 goto abort
call :mkebsboot
if errorlevel 1 goto abort
md %INSTANCE_HOME%
del %INSTANCE_HOME%\mkebsboot.cmd 2>NUL
echo @echo off>>%INSTANCE_HOME%\mkebsboot.cmd
echo title mkebsboot>>%INSTANCE_HOME%\mkebsboot.cmd
echo set PATH=c:\windows\;C:\windows\system32;c:\windows\system32\wbem>>%INSTANCE_HOME%\mkebsboot.cmd
echo set INSTANCE_NAME=mkebsboot>>%INSTANCE_HOME%\mkebsboot.cmd
echo set TMP_DIR=%TMP_DIR%>>%INSTANCE_HOME%\mkebsboot.cmd
echo set INSTANCE_NAME=%INSTANCE_NAME%>>%INSTANCE_HOME%\mkebsboot.cmd
echo set INSTANCE_HOME=%INSTANCE_HOME%>>%INSTANCE_HOME%\mkebsboot.cmd
echo set LOG_DIR=%LOG_DIR%>>%INSTANCE_HOME%\mkebsboot.cmd
echo cd /d %%INSTANCE_HOME%%>>%INSTANCE_HOME%\mkebsboot.cmd
md %INSTANCE_HOME%
del %INSTANCE_HOME%\mkebsboot.cmd 2>NUL
echo @echo off>>%INSTANCE_HOME%\mkebsboot.cmd
echo title mkebsboot>>%INSTANCE_HOME%\mkebsboot.cmd
echo set PATH=c:\windows\;C:\windows\system32;c:\windows\system32\wbem>>%INSTANCE_HOME%\mkebsboot.cmd
echo set INSTANCE_NAME=mkebsboot>>%INSTANCE_HOME%\mkebsboot.cmd
echo set TMP_DIR=%TMP_DIR%>>%INSTANCE_HOME%\mkebsboot.cmd
echo set INSTANCE_NAME=%INSTANCE_NAME%>>%INSTANCE_HOME%\mkebsboot.cmd
echo set INSTANCE_HOME=%INSTANCE_HOME%>>%INSTANCE_HOME%\mkebsboot.cmd
echo set LOG_DIR=%LOG_DIR%>>%INSTANCE_HOME%\mkebsboot.cmd
echo cd /d %%INSTANCE_HOME%%>>%INSTANCE_HOME%\mkebsboot.cmd
echo exit /b 0 >>%INSTANCE_HOME%\mkebsboot.cmd
GOTO END_SWITCH
:CASE_status
call :default
if errorlevel 1 goto abort
call :findPid %INSTANCE_NAME%
if errorlevel 1 goto abort
echo [%FOUND_PID%]
GOTO END_SWITCH
:CASE_stop
call :default
if errorlevel 1 goto abort
call :findPid %INSTANCE_NAME%
if errorlevel 1 goto abort
if defined FOUND_PID (
TASKKILL /F /T /PID %FOUND_PID% >NUL
)
GOTO END_SWITCH
:CASE_start
call :default
if errorlevel 1 goto abort
call :forget %INSTANCE_NAME% %INSTANCE_HOME%\%INSTANCE_NAME%.cmd %LOG_DIR%
if errorlevel 1 goto abort
GOTO END_SWITCH
:CASE_tail
call :default
if errorlevel 1 goto abort
tail %LOG_DIR%\stdout.log
GOTO END_SWITCH
:CASE_tailerr
call :default
if errorlevel 1 goto abort
tail %LOG_DIR%\stderr.log
GOTO END_SWITCH
:CASE_run
call :default
if errorlevel 1 goto abort
%INSTANCE_HOME%\%INSTANCE_NAME%.cmd
GOTO END_SWITCH
:END_SWITCH
exit /b 0

View File

@ -11,11 +11,11 @@ function default {
export INSTANCE_NAME="mkebsboot" export INSTANCE_NAME="mkebsboot"
export INSTANCE_HOME="/mnt/tmp" export INSTANCE_HOME="/mnt/tmp"
export LOG_DIR="/mnt/tmp" export LOG_DIR="/mnt/tmp"
return 0 return $?
} }
function mkebsboot { function mkebsboot {
export TMP_DIR="/mnt/tmp" export TMP_DIR="/mnt/tmp"
return 0 return $?
} }
function findPid { function findPid {
unset FOUND_PID; unset FOUND_PID;
@ -63,35 +63,40 @@ init)
mkdir -p $INSTANCE_HOME mkdir -p $INSTANCE_HOME
# create runscript header # create runscript header
cat > $INSTANCE_HOME/mkebsboot.sh <<END_OF_SCRIPT cat > $INSTANCE_HOME/mkebsboot.sh <<-'END_OF_JCLOUDS_SCRIPT'
#!/bin/bash #!/bin/bash
set +u set +u
shopt -s xpg_echo shopt -s xpg_echo
shopt -s expand_aliases shopt -s expand_aliases
PROMPT_COMMAND='echo -ne "\033]0;mkebsboot\007"'
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin PROMPT_COMMAND='echo -ne \"\033]0;mkebsboot\007\"'
export INSTANCE_NAME='mkebsboot' export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
export TMP_DIR='$TMP_DIR'
export INSTANCE_NAME='$INSTANCE_NAME' export INSTANCE_NAME='mkebsboot'
export INSTANCE_HOME='$INSTANCE_HOME' END_OF_JCLOUDS_SCRIPT
export LOG_DIR='$LOG_DIR' cat >> $INSTANCE_HOME/mkebsboot.sh <<-END_OF_JCLOUDS_SCRIPT
END_OF_SCRIPT export TMP_DIR='$TMP_DIR'
export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME'
export LOG_DIR='$LOG_DIR'
END_OF_JCLOUDS_SCRIPT
# add desired commands from the user # add desired commands from the user
cat >> $INSTANCE_HOME/mkebsboot.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/mkebsboot.sh <<-'END_OF_JCLOUDS_SCRIPT'
cd $INSTANCE_HOME cd $INSTANCE_HOME
cat >> /tmp/$USER/scripttest/temp.txt <<'END_OF_FILE' cat >> /tmp/$USER/scripttest/temp.txt <<-'END_OF_JCLOUDS_FILE'
hello world hello world
END_OF_FILE END_OF_JCLOUDS_FILE
find / find /
END_OF_SCRIPT END_OF_JCLOUDS_SCRIPT
# add runscript footer # add runscript footer
cat >> $INSTANCE_HOME/mkebsboot.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/mkebsboot.sh <<-'END_OF_JCLOUDS_SCRIPT'
exit 0 exit $?
END_OF_SCRIPT
END_OF_JCLOUDS_SCRIPT
chmod u+x $INSTANCE_HOME/mkebsboot.sh chmod u+x $INSTANCE_HOME/mkebsboot.sh
;; ;;
@ -125,4 +130,4 @@ run)
$INSTANCE_HOME/$INSTANCE_NAME.sh $INSTANCE_HOME/$INSTANCE_NAME.sh
;; ;;
esac esac
exit 0 exit $?

View File

@ -0,0 +1,162 @@
#!/bin/bash
set +u
shopt -s xpg_echo
shopt -s expand_aliases
unset PATH JAVA_HOME LD_LIBRARY_PATH
function abort {
echo "aborting: $@" 1>&2
exit 1
}
function default {
export INSTANCE_NAME="testcall"
export INSTANCE_HOME="/tmp/$INSTANCE_NAME"
export LOG_DIR="$INSTANCE_HOME"
return $?
}
function testcall {
return $?
}
function findPid {
unset FOUND_PID;
[ $# -eq 1 ] || {
abort "findPid requires a parameter of pattern to match"
return 1
}
local PATTERN="$1"; shift
local _FOUND=`ps auxwww|grep "$PATTERN"|grep -v " $0"|grep -v grep|grep -v $$|awk '{print $2}'`
[ -n "$_FOUND" ] && {
export FOUND_PID=$_FOUND
return 0
} || {
return 1
}
}
function forget {
unset FOUND_PID;
[ $# -eq 3 ] || {
abort "forget requires parameters INSTANCE_NAME SCRIPT LOG_DIR"
return 1
}
local INSTANCE_NAME="$1"; shift
local SCRIPT="$1"; shift
local LOG_DIR="$1"; shift
mkdir -p $LOG_DIR
findPid $INSTANCE_NAME
[ -n "$FOUND_PID" -a -f $LOG_DIR/stdout.log ] && {
echo $INSTANCE_NAME already running pid [$FOUND_PID]
return 1;
} || {
nohup $SCRIPT >$LOG_DIR/stdout.log 2>$LOG_DIR/stderr.log &
RETURN=$?
# this is generally followed by findPid, so we shouldn't exit
# immediately as the proc may not have registered in ps, yet
test $RETURN && sleep 1
return $RETURN;
}
}
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
case $1 in
init)
default || exit 1
testcall || exit 1
echo hello
mkdir -p $INSTANCE_HOME
# create runscript header
cat > $INSTANCE_HOME/testcall.sh <<-'END_OF_JCLOUDS_SCRIPT'
#!/bin/bash
set +u
shopt -s xpg_echo
shopt -s expand_aliases
PROMPT_COMMAND='echo -ne \"\033]0;testcall\007\"'
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
export INSTANCE_NAME='testcall'
END_OF_JCLOUDS_SCRIPT
cat >> $INSTANCE_HOME/testcall.sh <<-END_OF_JCLOUDS_SCRIPT
export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME'
export LOG_DIR='$LOG_DIR'
END_OF_JCLOUDS_SCRIPT
cat >> $INSTANCE_HOME/testcall.sh <<-'END_OF_JCLOUDS_SCRIPT'
function abort {
echo "aborting: $@" 1>&2
exit 1
}
function sourceEnvFile {
[ $# -eq 1 ] || {
abort "sourceEnvFile requires a parameter of the file to source"
return 1
}
local ENV_FILE="$1"; shift
. "$ENV_FILE" || {
abort "Please append 'return 0' to the end of '$ENV_FILE'"
return 1
}
return 0
}
END_OF_JCLOUDS_SCRIPT
# add desired commands from the user
cat >> $INSTANCE_HOME/testcall.sh <<-'END_OF_JCLOUDS_SCRIPT'
cd $INSTANCE_HOME
rm -f $INSTANCE_HOME/rc
trap 'echo $?>$INSTANCE_HOME/rc' 0 1 2 3 15
sourceEnvFile foo || exit 1
find /
END_OF_JCLOUDS_SCRIPT
# add runscript footer
cat >> $INSTANCE_HOME/testcall.sh <<-'END_OF_JCLOUDS_SCRIPT'
exit $?
END_OF_JCLOUDS_SCRIPT
chmod u+x $INSTANCE_HOME/testcall.sh
;;
status)
default || exit 1
findPid $INSTANCE_NAME || exit 1
echo [$FOUND_PID]
;;
stop)
default || exit 1
findPid $INSTANCE_NAME || exit 1
[ -n "$FOUND_PID" ] && {
echo stopping $FOUND_PID
kill -9 $FOUND_PID
}
;;
start)
default || exit 1
forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1
;;
stdout)
default || exit 1
cat $LOG_DIR/stdout.log
;;
stderr)
default || exit 1
cat $LOG_DIR/stderr.log
;;
exitstatus)
default || exit 1
[ -f $LOG_DIR/rc ] && cat $LOG_DIR/rc;;
tail)
default || exit 1
tail $LOG_DIR/stdout.log
;;
tailerr)
default || exit 1
tail $LOG_DIR/stderr.log
;;
run)
default || exit 1
$INSTANCE_HOME/$INSTANCE_NAME.sh
;;
esac
exit $?

View File

@ -2,20 +2,20 @@ setupPublicCurl || return 1
curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.oracle.com/otn-pub/java/jdk/7/jdk-7-linux-x64.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -) curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.oracle.com/otn-pub/java/jdk/7/jdk-7-linux-x64.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -)
mv /usr/local/jdk* /usr/local/jdk/ mv /usr/local/jdk* /usr/local/jdk/
test -n "$SUDO_USER" && test -n "$SUDO_USER" &&
cat >> /home/$SUDO_USER/.bashrc <<'END_OF_FILE' cat >> /home/$SUDO_USER/.bashrc <<-'END_OF_JCLOUDS_FILE'
export JAVA_HOME=/usr/local/jdk export JAVA_HOME=/usr/local/jdk
export PATH=$JAVA_HOME/bin:$PATH export PATH=$JAVA_HOME/bin:$PATH
END_OF_FILE END_OF_JCLOUDS_FILE
cat >> /etc/bashrc <<'END_OF_FILE' cat >> /etc/bashrc <<-'END_OF_JCLOUDS_FILE'
export JAVA_HOME=/usr/local/jdk export JAVA_HOME=/usr/local/jdk
export PATH=$JAVA_HOME/bin:$PATH export PATH=$JAVA_HOME/bin:$PATH
END_OF_FILE END_OF_JCLOUDS_FILE
cat >> $HOME/.bashrc <<'END_OF_FILE' cat >> $HOME/.bashrc <<-'END_OF_JCLOUDS_FILE'
export JAVA_HOME=/usr/local/jdk export JAVA_HOME=/usr/local/jdk
export PATH=$JAVA_HOME/bin:$PATH export PATH=$JAVA_HOME/bin:$PATH
END_OF_FILE END_OF_JCLOUDS_FILE
cat >> /etc/skel/.bashrc <<'END_OF_FILE' cat >> /etc/skel/.bashrc <<-'END_OF_JCLOUDS_FILE'
export JAVA_HOME=/usr/local/jdk export JAVA_HOME=/usr/local/jdk
export PATH=$JAVA_HOME/bin:$PATH export PATH=$JAVA_HOME/bin:$PATH
END_OF_FILE END_OF_JCLOUDS_FILE
ln -fs /usr/local/jdk/bin/java /usr/bin/java ln -fs /usr/local/jdk/bin/java /usr/bin/java

View File

@ -9,12 +9,12 @@ function abort {
} }
function default { function default {
export INSTANCE_NAME="install_jdk" export INSTANCE_NAME="install_jdk"
export INSTANCE_HOME="$HOME/instances/install_jdk" export INSTANCE_HOME="/tmp/$INSTANCE_NAME"
export LOG_DIR="$HOME/instances/install_jdk" export LOG_DIR="$INSTANCE_HOME"
return 0 return $?
} }
function install_jdk { function install_jdk {
return 0 return $?
} }
function findPid { function findPid {
unset FOUND_PID; unset FOUND_PID;
@ -62,35 +62,41 @@ init)
mkdir -p $INSTANCE_HOME mkdir -p $INSTANCE_HOME
# create runscript header # create runscript header
cat > $INSTANCE_HOME/install_jdk.sh <<END_OF_SCRIPT cat > $INSTANCE_HOME/install_jdk.sh <<-'END_OF_JCLOUDS_SCRIPT'
#!/bin/bash #!/bin/bash
set +u set +u
shopt -s xpg_echo shopt -s xpg_echo
shopt -s expand_aliases shopt -s expand_aliases
PROMPT_COMMAND='echo -ne "\033]0;install_jdk\007"'
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin PROMPT_COMMAND='echo -ne \"\033]0;install_jdk\007\"'
export INSTANCE_NAME='install_jdk' export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME' export INSTANCE_NAME='install_jdk'
export LOG_DIR='$LOG_DIR' END_OF_JCLOUDS_SCRIPT
function abort { cat >> $INSTANCE_HOME/install_jdk.sh <<-END_OF_JCLOUDS_SCRIPT
echo "aborting: \$@" 1>&2 export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME'
export LOG_DIR='$LOG_DIR'
END_OF_JCLOUDS_SCRIPT
cat >> $INSTANCE_HOME/install_jdk.sh <<-'END_OF_JCLOUDS_SCRIPT'
function abort {
echo "aborting: $@" 1>&2
exit 1 exit 1
} }
alias apt-get-install="apt-get install -f -y -qq --force-yes" alias apt-get-install="apt-get install -f -y -qq --force-yes"
alias apt-get-upgrade="(apt-get update -qq&&apt-get upgrade -y -qq)" alias apt-get-upgrade="(apt-get update -qq&&apt-get upgrade -y -qq)"
function ensure_cmd_or_install_package_apt(){ function ensure_cmd_or_install_package_apt(){
local cmd=\$1 local cmd=$1
local pkg=\$2 local pkg=$2
hash \$cmd 2>/dev/null || apt-get-install \$pkg || ( apt-get-upgrade && apt-get-install \$pkg ) hash $cmd 2>/dev/null || apt-get-install $pkg || ( apt-get-upgrade && apt-get-install $pkg )
} }
function ensure_cmd_or_install_package_yum(){ function ensure_cmd_or_install_package_yum(){
local cmd=\$1 local cmd=$1
local pkg=\$2 local pkg=$2
hash \$cmd 2>/dev/null || yum --nogpgcheck -y ensure \$pkg hash $cmd 2>/dev/null || yum --nogpgcheck -y ensure $pkg
} }
function ensure_netutils_apt() { function ensure_netutils_apt() {
@ -106,7 +112,7 @@ function ensure_netutils_yum() {
# most network services require that the hostname is in # most network services require that the hostname is in
# the /etc/hosts file, or they won't operate # the /etc/hosts file, or they won't operate
function ensure_hostname_in_hosts() { function ensure_hostname_in_hosts() {
egrep -q `hostname` /etc/hosts || awk -v hostname=`hostname` 'END { print \$1" "hostname }' /proc/net/arp >> /etc/hosts egrep -q `hostname` /etc/hosts || awk -v hostname=`hostname` 'END { print $1" "hostname }' /proc/net/arp >> /etc/hosts
} }
# download locations for many services are at public dns # download locations for many services are at public dns
@ -127,39 +133,43 @@ function setupPublicCurl() {
ensure_can_resolve_public_dns ensure_can_resolve_public_dns
return 0 return 0
} }
END_OF_SCRIPT
END_OF_JCLOUDS_SCRIPT
# add desired commands from the user # add desired commands from the user
cat >> $INSTANCE_HOME/install_jdk.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/install_jdk.sh <<-'END_OF_JCLOUDS_SCRIPT'
cd $INSTANCE_HOME cd $INSTANCE_HOME
setupPublicCurl || exit 1 rm -f $INSTANCE_HOME/rc
curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.oracle.com/otn-pub/java/jdk/7/jdk-7-linux-x64.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -) trap 'echo $?>$INSTANCE_HOME/rc' 0 1 2 3 15
mv /usr/local/jdk* /usr/local/jdk/ setupPublicCurl || exit 1
test -n "$SUDO_USER" && curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.oracle.com/otn-pub/java/jdk/7/jdk-7-linux-x64.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -)
cat >> /home/$SUDO_USER/.bashrc <<'END_OF_FILE' mv /usr/local/jdk* /usr/local/jdk/
export JAVA_HOME=/usr/local/jdk test -n "$SUDO_USER" &&
export PATH=$JAVA_HOME/bin:$PATH cat >> /home/$SUDO_USER/.bashrc <<-'END_OF_JCLOUDS_FILE'
END_OF_FILE export JAVA_HOME=/usr/local/jdk
cat >> /etc/bashrc <<'END_OF_FILE' export PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME=/usr/local/jdk END_OF_JCLOUDS_FILE
export PATH=$JAVA_HOME/bin:$PATH cat >> /etc/bashrc <<-'END_OF_JCLOUDS_FILE'
END_OF_FILE export JAVA_HOME=/usr/local/jdk
cat >> $HOME/.bashrc <<'END_OF_FILE' export PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME=/usr/local/jdk END_OF_JCLOUDS_FILE
export PATH=$JAVA_HOME/bin:$PATH cat >> $HOME/.bashrc <<-'END_OF_JCLOUDS_FILE'
END_OF_FILE export JAVA_HOME=/usr/local/jdk
cat >> /etc/skel/.bashrc <<'END_OF_FILE' export PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME=/usr/local/jdk END_OF_JCLOUDS_FILE
export PATH=$JAVA_HOME/bin:$PATH cat >> /etc/skel/.bashrc <<-'END_OF_JCLOUDS_FILE'
END_OF_FILE export JAVA_HOME=/usr/local/jdk
ln -fs /usr/local/jdk/bin/java /usr/bin/java export PATH=$JAVA_HOME/bin:$PATH
END_OF_JCLOUDS_FILE
ln -fs /usr/local/jdk/bin/java /usr/bin/java
END_OF_SCRIPT END_OF_JCLOUDS_SCRIPT
# add runscript footer # add runscript footer
cat >> $INSTANCE_HOME/install_jdk.sh <<'END_OF_SCRIPT' cat >> $INSTANCE_HOME/install_jdk.sh <<-'END_OF_JCLOUDS_SCRIPT'
exit 0 exit $?
END_OF_SCRIPT
END_OF_JCLOUDS_SCRIPT
chmod u+x $INSTANCE_HOME/install_jdk.sh chmod u+x $INSTANCE_HOME/install_jdk.sh
;; ;;
@ -180,6 +190,17 @@ start)
default || exit 1 default || exit 1
forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1 forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1
;; ;;
stdout)
default || exit 1
cat $LOG_DIR/stdout.log
;;
stderr)
default || exit 1
cat $LOG_DIR/stderr.log
;;
exitstatus)
default || exit 1
[ -f $LOG_DIR/rc ] && cat $LOG_DIR/rc;;
tail) tail)
default || exit 1 default || exit 1
tail $LOG_DIR/stdout.log tail $LOG_DIR/stdout.log
@ -193,4 +214,4 @@ run)
$INSTANCE_HOME/$INSTANCE_NAME.sh $INSTANCE_HOME/$INSTANCE_NAME.sh
;; ;;
esac esac
exit 0 exit $?

View File

@ -1,17 +0,0 @@
md %TEMP%\%USERNAME%\scripttest
del %TEMP%\%USERNAME%\scripttest\yahooprod.cmd 2>NUL
echo @echo off>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
echo title yahooprod>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
echo set PATH=c:\windows\;C:\windows\system32;c:\windows\system32\wbem>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
echo set INSTANCE_NAME=yahooprod>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
echo set JAVA_HOME=%JAVA_HOME%>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
echo cd /d %TEMP%\%USERNAME%\scripttest>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
md %TEMP%\%USERNAME%\scripttest
del %TEMP%\%USERNAME%\scripttest\yahooprod.cmd 2>NUL
echo @echo off>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
echo title yahooprod>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
echo set PATH=c:\windows\;C:\windows\system32;c:\windows\system32\wbem>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
echo set INSTANCE_NAME=yahooprod>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
echo set JAVA_HOME=%JAVA_HOME%>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
echo cd /d %TEMP%\%USERNAME%\scripttest>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
echo exit /b 0 >>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd

View File

@ -1,33 +1,38 @@
mkdir -p /tmp/$USER/scripttest mkdir -p /tmp/$USER/scripttest
# create runscript header # create runscript header
cat > /tmp/$USER/scripttest/yahooprod.sh <<END_OF_SCRIPT cat > /tmp/$USER/scripttest/yahooprod.sh <<-'END_OF_JCLOUDS_SCRIPT'
#!/bin/bash #!/bin/bash
set +u set +u
shopt -s xpg_echo shopt -s xpg_echo
shopt -s expand_aliases shopt -s expand_aliases
PROMPT_COMMAND='echo -ne "\033]0;yahooprod\007"'
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin PROMPT_COMMAND='echo -ne \"\033]0;yahooprod\007\"'
export INSTANCE_NAME='yahooprod' export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
export JAVA_HOME='$JAVA_HOME'
END_OF_SCRIPT export INSTANCE_NAME='yahooprod'
END_OF_JCLOUDS_SCRIPT
cat >> /tmp/$USER/scripttest/yahooprod.sh <<-END_OF_JCLOUDS_SCRIPT
export JAVA_HOME='$JAVA_HOME'
END_OF_JCLOUDS_SCRIPT
# add desired commands from the user # add desired commands from the user
cat >> /tmp/$USER/scripttest/yahooprod.sh <<'END_OF_SCRIPT' cat >> /tmp/$USER/scripttest/yahooprod.sh <<-'END_OF_JCLOUDS_SCRIPT'
cd /tmp/$USER/scripttest cd /tmp/$USER/scripttest
echo hello echo hello
cat >> /tmp/$USER/scripttest/temp.txt <<'END_OF_FILE' cat >> /tmp/$USER/scripttest/temp.txt <<-'END_OF_JCLOUDS_FILE'
hello world hello world
END_OF_FILE END_OF_JCLOUDS_FILE
echo $JAVA_HOME/bin/java -DinstanceName=$INSTANCE_NAME myServer.Main echo $JAVA_HOME/bin/java -DinstanceName=$INSTANCE_NAME myServer.Main
END_OF_SCRIPT END_OF_JCLOUDS_SCRIPT
# add runscript footer # add runscript footer
cat >> /tmp/$USER/scripttest/yahooprod.sh <<'END_OF_SCRIPT' cat >> /tmp/$USER/scripttest/yahooprod.sh <<-'END_OF_JCLOUDS_SCRIPT'
exit 0 exit $?
END_OF_SCRIPT
END_OF_JCLOUDS_SCRIPT
chmod u+x /tmp/$USER/scripttest/yahooprod.sh chmod u+x /tmp/$USER/scripttest/yahooprod.sh

View File

@ -9,7 +9,7 @@ function abort {
} }
function default { function default {
export RUNTIME="Moo" export RUNTIME="Moo"
return 0 return $?
} }
export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
case $1 in case $1 in
@ -22,10 +22,10 @@ stop)
echo stop $RUNTIME echo stop $RUNTIME
;; ;;
status) status)
cat >> /tmp/$USER/scripttest/temp.txt <<'END_OF_FILE' cat >> /tmp/$USER/scripttest/temp.txt <<-'END_OF_JCLOUDS_FILE'
hello world hello world
END_OF_FILE END_OF_JCLOUDS_FILE
echo "the following should be []: [$RUNTIME]" echo "the following should be []: [$RUNTIME]"
;; ;;
esac esac
exit 0 exit $?

View File

@ -28,4 +28,4 @@ findPid $@ || exit 1
echo stopping $FOUND_PID echo stopping $FOUND_PID
kill -9 $FOUND_PID kill -9 $FOUND_PID
} }
exit 0 exit $?