mirror of https://github.com/apache/jclouds.git
Extended the support for running scripts as a part of Compute Service. Now scripts can be run as root. Also, credentials are optional and moved to RunScriptOptions.
TODO next: tests to verify non-root execution of the scripts
This commit is contained in:
parent
882bf5f651
commit
5ff12c4a73
|
@ -158,23 +158,22 @@ public interface ComputeService {
|
|||
/**
|
||||
* Runs the script without any additional options
|
||||
*
|
||||
* @see #runScriptOnNodesWithTag(String, org.jclouds.domain.Credentials,
|
||||
* @see #runScriptOnNodesWithTag(String,
|
||||
* byte[], org.jclouds.compute.options.RunScriptOptions)
|
||||
*/
|
||||
Map<String, ExecResponse> runScriptOnNodesWithTag(String tag, Credentials credentials,
|
||||
Map<String, ExecResponse> runScriptOnNodesWithTag(String tag,
|
||||
byte[] runScript);
|
||||
|
||||
/**
|
||||
* Run the script on all nodes with the specific tag.
|
||||
*
|
||||
* @param tag tag to look up the nodes
|
||||
* @param credentials credentials to use (same for all nodes)
|
||||
* @param runScript script to run in byte format. If the script is a string, use
|
||||
* {@link String#getBytes()} to retrieve the bytes
|
||||
* @param options nullable options to how to run the script
|
||||
* @return map with node identifiers and corresponding responses
|
||||
*/
|
||||
Map<String, ExecResponse> runScriptOnNodesWithTag(String tag, Credentials credentials,
|
||||
Map<String, ExecResponse> runScriptOnNodesWithTag(String tag,
|
||||
byte[] runScript, RunScriptOptions options);
|
||||
|
||||
}
|
||||
|
|
|
@ -323,26 +323,24 @@ public class BaseComputeService implements ComputeService {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see #runScriptOnNodesWithTag(String, org.jclouds.domain.Credentials, byte[],
|
||||
* @see #runScriptOnNodesWithTag(String, byte[],
|
||||
* org.jclouds.compute.options.RunScriptOptions)
|
||||
*/
|
||||
public Map<String, ExecResponse> runScriptOnNodesWithTag(String tag, Credentials credentials,
|
||||
public Map<String, ExecResponse> runScriptOnNodesWithTag(String tag,
|
||||
byte[] runScript) {
|
||||
return runScriptOnNodesWithTag(tag, credentials, runScript, RunScriptOptions.NONE);
|
||||
return runScriptOnNodesWithTag(tag, runScript, RunScriptOptions.NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the script on all nodes with the specific tag.
|
||||
*
|
||||
* @param tag tag to look up the nodes
|
||||
* @param credentials nullable credentials to use (same for all nodes).
|
||||
* @param runScript script to run in byte format. If the script is a string, use
|
||||
* {@link String#getBytes()} to retrieve the bytes
|
||||
* @param options nullable options to how to run the script
|
||||
* @param options nullable options to how to run the script, whether to override credentials
|
||||
* @return map with node identifiers and corresponding responses
|
||||
*/
|
||||
public Map<String, ExecResponse> runScriptOnNodesWithTag(String tag, @Nullable Credentials credentials,
|
||||
byte[] runScript, @Nullable RunScriptOptions options) {
|
||||
public Map<String, ExecResponse> runScriptOnNodesWithTag(String tag, byte[] runScript, @Nullable RunScriptOptions options) {
|
||||
checkNotEmpty(tag, "Tag must be provided");
|
||||
checkNotNull(runScript,
|
||||
"The script (represented by bytes array - use \"script\".getBytes() must be provided");
|
||||
|
@ -354,18 +352,19 @@ public class BaseComputeService implements ComputeService {
|
|||
for(NodeMetadata node : nodes.values()) {
|
||||
if(NodeState.RUNNING != node.getState()) continue; //make sure the node is active
|
||||
|
||||
if(options.isOverrideCredentials()) {
|
||||
if(options.getOverrideCredentials() != null) {
|
||||
//override the credentials with provided to this method
|
||||
checkNotNull(credentials, "If the credentials need to be overridden, they can't be null");
|
||||
node = ComputeUtils.installNewCredentials(node, credentials);
|
||||
node = ComputeUtils.installNewCredentials(node, options.getOverrideCredentials());
|
||||
} else {
|
||||
//don't override
|
||||
checkNotNull(node.getCredentials(), "If the default credentials need to be used, they can't be null");
|
||||
}
|
||||
|
||||
//todo: execute script as root if required
|
||||
|
||||
ComputeUtils.SshCallable<?> callable = utils.runScriptOnNode(node, "computeserv.sh", runScript);
|
||||
ComputeUtils.SshCallable<?> callable;
|
||||
if(options.isRunAsRoot())
|
||||
callable = utils.runScriptOnNode(node, "computeserv.sh", runScript);
|
||||
else
|
||||
callable = utils.runScriptOnNodeAsDefaultUser(node, "computeserv.sh", runScript);
|
||||
|
||||
Map<ComputeUtils.SshCallable<?>, ?> scriptRunResults = utils.runCallablesOnNode(node,
|
||||
Sets.newHashSet(callable),
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
*/
|
||||
package org.jclouds.compute.options;
|
||||
|
||||
import org.jclouds.domain.Credentials;
|
||||
|
||||
/**
|
||||
* Enables additional options for running a script.
|
||||
*
|
||||
|
@ -30,16 +32,16 @@ public class RunScriptOptions {
|
|||
* <ul>
|
||||
* <li>override the credentials with ones supplied in
|
||||
* call to {@link org.jclouds.compute.ComputeService#runScriptOnNodesWithTag}</li>
|
||||
* <li>do not run the script as root (run with current privileges)</li>
|
||||
* <li>run the script as root (versus running with current privileges)</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static final RunScriptOptions NONE = new RunScriptOptions();
|
||||
|
||||
private boolean overrideCredentials = true;
|
||||
private boolean runAsRoot = false;
|
||||
private Credentials overridingCredentials;
|
||||
private boolean runAsRoot = true;
|
||||
|
||||
private void overrideCredentials(boolean overrideCredentials) {
|
||||
this.overrideCredentials = overrideCredentials;
|
||||
private void withOverridingCredentials(Credentials overridingCredentials) {
|
||||
this.overridingCredentials = overridingCredentials;
|
||||
}
|
||||
|
||||
private void runAsRoot(boolean runAsRoot) {
|
||||
|
@ -52,13 +54,13 @@ public class RunScriptOptions {
|
|||
* By default, true.
|
||||
* @return value
|
||||
*/
|
||||
public boolean isOverrideCredentials() {
|
||||
return overrideCredentials;
|
||||
public Credentials getOverrideCredentials() {
|
||||
return overridingCredentials;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to run the script as root (run with current privileges).
|
||||
* By default, false.
|
||||
* Whether to run the script as root (or run with current privileges).
|
||||
* By default, true.
|
||||
* @return value
|
||||
*/
|
||||
public boolean isRunAsRoot() {
|
||||
|
@ -68,9 +70,9 @@ public class RunScriptOptions {
|
|||
public static class Builder {
|
||||
private RunScriptOptions options;
|
||||
|
||||
public Builder overrideCredentials(boolean value) {
|
||||
public Builder overrideCredentials(Credentials credentials) {
|
||||
if(options == null) options = new RunScriptOptions();
|
||||
options.overrideCredentials(value);
|
||||
options.withOverridingCredentials(credentials);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -130,6 +130,10 @@ public class ComputeUtils {
|
|||
return new RunScriptOnNode(runScriptNotRunning, node, scriptName, script);
|
||||
}
|
||||
|
||||
public RunScriptOnNode runScriptOnNodeAsDefaultUser(NodeMetadata node, String scriptName, byte[] script) {
|
||||
return new RunScriptOnNode(runScriptNotRunning, node, scriptName, script, false);
|
||||
}
|
||||
|
||||
public Map<SshCallable<?>, ?> runCallablesOnNode(NodeMetadata node, Iterable<? extends SshCallable<?>> parallel,
|
||||
@Nullable SshCallable<?> last) {
|
||||
checkState(this.sshFactory != null, "runScript requested, but no SshModule configured");
|
||||
|
@ -210,6 +214,7 @@ public class ComputeUtils {
|
|||
private final NodeMetadata node;
|
||||
private final String scriptName;
|
||||
private final byte[] script;
|
||||
private final boolean runAsRoot;
|
||||
private Logger logger = Logger.NULL;
|
||||
|
||||
RunScriptOnNode(@Named("NOT_RUNNING") Predicate<SshClient> runScriptNotRunning,
|
||||
|
@ -221,6 +226,19 @@ public class ComputeUtils {
|
|||
.<String, String> of(), Iterables.toArray(Splitter.on("\n").split(
|
||||
new String(checkNotNull(script, "script"))), String.class)).build(OsFamily.UNIX)
|
||||
.getBytes();
|
||||
this.runAsRoot = true;
|
||||
}
|
||||
|
||||
RunScriptOnNode(@Named("NOT_RUNNING") Predicate<SshClient> runScriptNotRunning,
|
||||
NodeMetadata node, String scriptName, byte[] script, boolean runAsRoot) {
|
||||
this.runScriptNotRunning = runScriptNotRunning;
|
||||
this.node = checkNotNull(node, "node");
|
||||
this.scriptName = checkNotNull(scriptName, "scriptName");
|
||||
this.script = new InitBuilder("runscript", "/tmp", "/tmp", ImmutableMap
|
||||
.<String, String> of(), Iterables.toArray(Splitter.on("\n").split(
|
||||
new String(checkNotNull(script, "script"))), String.class)).build(OsFamily.UNIX)
|
||||
.getBytes();
|
||||
this.runAsRoot = runAsRoot;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -228,21 +246,9 @@ public class ComputeUtils {
|
|||
ssh.put(scriptName, new ByteArrayInputStream(script));
|
||||
ExecResponse returnVal = ssh.exec("chmod 755 " + scriptName);
|
||||
returnVal = ssh.exec("./" + scriptName + " init");
|
||||
if (node.getCredentials().account.equals("root")) {
|
||||
logger.debug(">> running %s as %s@%s", scriptName, node.getCredentials().account,
|
||||
Iterables.get(node.getPublicAddresses(), 0).getHostAddress());
|
||||
returnVal = ssh.exec("./" + scriptName + " start");
|
||||
} else if (isKeyAuth(node)) {
|
||||
logger.debug(">> running sudo %s as %s@%s", scriptName, node.getCredentials().account,
|
||||
Iterables.get(node.getPublicAddresses(), 0).getHostAddress());
|
||||
returnVal = ssh.exec("sudo ./" + scriptName + " start");
|
||||
} else {
|
||||
logger.debug(">> running sudo -S %s as %s@%s", scriptName,
|
||||
node.getCredentials().account, Iterables.get(node.getPublicAddresses(), 0)
|
||||
.getHostAddress());
|
||||
returnVal = ssh.exec(String.format("echo %s|sudo -S ./%s", node.getCredentials().key,
|
||||
scriptName + " start"));
|
||||
}
|
||||
|
||||
if(runAsRoot) returnVal = runScriptAsRoot();
|
||||
else returnVal = runScriptAsDefaultUser();
|
||||
runScriptNotRunning.apply(ssh);
|
||||
logger.debug("<< complete(%d)", returnVal.getExitCode());
|
||||
return returnVal;
|
||||
|
@ -253,6 +259,31 @@ public class ComputeUtils {
|
|||
this.logger = checkNotNull(logger, "logger");
|
||||
this.ssh = checkNotNull(ssh, "ssh");
|
||||
}
|
||||
|
||||
private ExecResponse runScriptAsRoot() {
|
||||
if (node.getCredentials().account.equals("root")) {
|
||||
logger.debug(">> running %s as %s@%s", scriptName, node.getCredentials().account,
|
||||
Iterables.get(node.getPublicAddresses(), 0).getHostAddress());
|
||||
return ssh.exec("./" + scriptName + " start");
|
||||
} else if (isKeyAuth(node)) {
|
||||
logger.debug(">> running sudo %s as %s@%s", scriptName, node.getCredentials().account,
|
||||
Iterables.get(node.getPublicAddresses(), 0).getHostAddress());
|
||||
return ssh.exec("sudo ./" + scriptName + " start");
|
||||
} else {
|
||||
logger.debug(">> running sudo -S %s as %s@%s", scriptName,
|
||||
node.getCredentials().account, Iterables.get(node.getPublicAddresses(), 0)
|
||||
.getHostAddress());
|
||||
return ssh.exec(String.format("echo %s|sudo -S ./%s", node.getCredentials().key,
|
||||
scriptName + " start"));
|
||||
}
|
||||
}
|
||||
|
||||
private ExecResponse runScriptAsDefaultUser() {
|
||||
logger.debug(">> running script %s as %s@%s", scriptName,
|
||||
node.getCredentials().account, Iterables.get(node.getPublicAddresses(), 0)
|
||||
.getHostAddress());
|
||||
return ssh.exec(String.format("./%s", scriptName + " start"));
|
||||
}
|
||||
}
|
||||
|
||||
public static class InstallRSAPrivateKey implements SshCallable<ExecResponse> {
|
||||
|
|
Loading…
Reference in New Issue