mirror of https://github.com/apache/jclouds.git
Issue 614:Add Visitor pattern support for scriptbuilder Statements
This commit is contained in:
parent
0a28bbdb8a
commit
b56f08b9a5
|
@ -28,14 +28,17 @@ 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.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;
|
||||||
import org.jclouds.scriptbuilder.InitBuilder;
|
import org.jclouds.scriptbuilder.InitBuilder;
|
||||||
|
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;
|
||||||
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.ssh.SshClient;
|
import org.jclouds.ssh.SshClient;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
@ -52,15 +55,16 @@ import com.google.inject.assistedinject.AssistedInject;
|
||||||
*/
|
*/
|
||||||
public class RunScriptOnNodeAsInitScriptUsingSsh implements RunScriptOnNode {
|
public class RunScriptOnNodeAsInitScriptUsingSsh implements RunScriptOnNode {
|
||||||
public static final String PROPERTY_PUSH_INIT_SCRIPT_VIA_SFTP = "jclouds.compute.push-init-script-via-sftp";
|
public static final String PROPERTY_PUSH_INIT_SCRIPT_VIA_SFTP = "jclouds.compute.push-init-script-via-sftp";
|
||||||
|
public static final String PROPERTY_INIT_SCRIPT_PATTERN = "jclouds.compute.init-script-pattern";
|
||||||
@Resource
|
@Resource
|
||||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||||
protected Logger logger = Logger.NULL;
|
protected Logger logger = Logger.NULL;
|
||||||
|
|
||||||
protected final Function<NodeMetadata, SshClient> sshFactory;
|
protected final Function<NodeMetadata, SshClient> sshFactory;
|
||||||
protected final NodeMetadata node;
|
protected NodeMetadata node;
|
||||||
protected final Statement init;
|
protected final InitBuilder init;
|
||||||
protected final String name;
|
|
||||||
protected final boolean runAsRoot;
|
protected final boolean runAsRoot;
|
||||||
|
protected final String initFile;
|
||||||
|
|
||||||
protected SshClient ssh;
|
protected SshClient ssh;
|
||||||
|
|
||||||
|
@ -72,6 +76,15 @@ public class RunScriptOnNodeAsInitScriptUsingSsh implements RunScriptOnNode {
|
||||||
@Named(PROPERTY_PUSH_INIT_SCRIPT_VIA_SFTP)
|
@Named(PROPERTY_PUSH_INIT_SCRIPT_VIA_SFTP)
|
||||||
private boolean pushInitViaSftp = true;
|
private boolean pushInitViaSftp = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* determines the naming convention of init scripts.
|
||||||
|
*
|
||||||
|
* ex. {@code /tmp/init-%s}
|
||||||
|
*/
|
||||||
|
@Inject(optional = true)
|
||||||
|
@Named(PROPERTY_INIT_SCRIPT_PATTERN)
|
||||||
|
private String initScriptPattern = "/tmp/init-%s";
|
||||||
|
|
||||||
@AssistedInject
|
@AssistedInject
|
||||||
public RunScriptOnNodeAsInitScriptUsingSsh(Function<NodeMetadata, SshClient> sshFactory,
|
public RunScriptOnNodeAsInitScriptUsingSsh(Function<NodeMetadata, SshClient> sshFactory,
|
||||||
@Assisted NodeMetadata node, @Assisted Statement script, @Assisted RunScriptOptions options) {
|
@Assisted NodeMetadata node, @Assisted Statement script, @Assisted RunScriptOptions options) {
|
||||||
|
@ -84,9 +97,9 @@ public class RunScriptOnNodeAsInitScriptUsingSsh implements RunScriptOnNode {
|
||||||
else
|
else
|
||||||
name = "jclouds-script-" + System.currentTimeMillis();
|
name = "jclouds-script-" + System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
this.name = checkNotNull(name, "name");
|
|
||||||
this.init = checkNotNull(script, "script") instanceof InitBuilder ? InitBuilder.class.cast(script)
|
this.init = checkNotNull(script, "script") instanceof InitBuilder ? InitBuilder.class.cast(script)
|
||||||
: createInitScript(name, script);
|
: createInitScript(name, script);
|
||||||
|
this.initFile = String.format(initScriptPattern, name);
|
||||||
this.runAsRoot = options.shouldRunAsRoot();
|
this.runAsRoot = options.shouldRunAsRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,22 +126,48 @@ public class RunScriptOnNodeAsInitScriptUsingSsh implements RunScriptOnNode {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void refreshSshIfNewAdminCredentialsConfigured(AdminAccess input) {
|
||||||
|
if (input.getAdminCredentials() != null && input.shouldGrantSudoToAdminUser()) {
|
||||||
|
ssh.disconnect();
|
||||||
|
logger.debug(">> reconnecting as %s@%s", input.getAdminCredentials().identity, ssh.getHostAddress());
|
||||||
|
ssh = sshFactory.apply(node = NodeMetadataBuilder.fromNodeMetadata(node).adminPassword(null).credentials(
|
||||||
|
input.getAdminCredentials()).build());
|
||||||
|
ssh.connect();
|
||||||
|
setupLinkToInitFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ssh client is initialized through this call.
|
* ssh client is initialized through this call.
|
||||||
*/
|
*/
|
||||||
protected ExecResponse doCall() {
|
protected ExecResponse doCall() {
|
||||||
if (pushInitViaSftp) {
|
if (pushInitViaSftp) {
|
||||||
ssh.put(name, init.render(OsFamily.UNIX));
|
ssh.put(initFile, init.render(OsFamily.UNIX));
|
||||||
} else {
|
} else {
|
||||||
ssh.exec("rm " + name);
|
ssh.exec("rm " + initFile);
|
||||||
ssh.exec(Statements.appendFile(name, Splitter.on('\n').split(init.render(OsFamily.UNIX)),
|
ssh.exec(Statements.appendFile(initFile, Splitter.on('\n').split(init.render(OsFamily.UNIX)),
|
||||||
AppendFile.MARKER + "_" + name).render(OsFamily.UNIX));
|
AppendFile.MARKER + "_" + init.getInstanceName()).render(OsFamily.UNIX));
|
||||||
}
|
}
|
||||||
ssh.exec("chmod 755 " + name);
|
|
||||||
|
ssh.exec("chmod 755 " + initFile);
|
||||||
|
setupLinkToInitFile();
|
||||||
|
|
||||||
runAction("init");
|
runAction("init");
|
||||||
|
init.getInitStatement().accept(new AdminAccessVisitor() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(AdminAccess input) {
|
||||||
|
refreshSshIfNewAdminCredentialsConfigured(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
return runAction("start");
|
return runAction("start");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void setupLinkToInitFile() {
|
||||||
|
ssh.exec(String.format("ln -fs %s %s", initFile, init.getInstanceName()));
|
||||||
|
}
|
||||||
|
|
||||||
protected ExecResponse runAction(String action) {
|
protected ExecResponse runAction(String action) {
|
||||||
ExecResponse returnVal;
|
ExecResponse returnVal;
|
||||||
String command = (runAsRoot) ? execScriptAsRoot(action) : execScriptAsDefaultUser(action);
|
String command = (runAsRoot) ? execScriptAsRoot(action) : execScriptAsDefaultUser(action);
|
||||||
|
@ -152,17 +191,17 @@ public class RunScriptOnNodeAsInitScriptUsingSsh implements RunScriptOnNode {
|
||||||
public String execScriptAsRoot(String action) {
|
public String execScriptAsRoot(String action) {
|
||||||
String command;
|
String command;
|
||||||
if (node.getCredentials().identity.equals("root")) {
|
if (node.getCredentials().identity.equals("root")) {
|
||||||
command = "./" + name + " " + action;
|
command = "./" + init.getInstanceName() + " " + action;
|
||||||
} else if (node.getAdminPassword() != null) {
|
} else if (node.getAdminPassword() != null) {
|
||||||
command = String.format("echo '%s'|sudo -S ./%s %s", node.getAdminPassword(), name, action);
|
command = String.format("echo '%s'|sudo -S ./%s %s", node.getAdminPassword(), init.getInstanceName(), action);
|
||||||
} else {
|
} else {
|
||||||
command = "sudo ./" + name + " " + action;
|
command = "sudo ./" + init.getInstanceName() + " " + action;
|
||||||
}
|
}
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String execScriptAsDefaultUser(String action) {
|
protected String execScriptAsDefaultUser(String action) {
|
||||||
return "./" + name + " " + action;
|
return "./" + initFile + " " + action;
|
||||||
}
|
}
|
||||||
|
|
||||||
public NodeMetadata getNode() {
|
public NodeMetadata getNode() {
|
||||||
|
@ -171,7 +210,8 @@ public class RunScriptOnNodeAsInitScriptUsingSsh implements RunScriptOnNode {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return Objects.toStringHelper(this).add("node", node).add("name", name).add("runAsRoot", runAsRoot).toString();
|
return Objects.toStringHelper(this).add("node", node).add("name", init.getInstanceName()).add("runAsRoot",
|
||||||
|
runAsRoot).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -53,13 +53,14 @@ public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete extends Ru
|
||||||
@Override
|
@Override
|
||||||
public ExecResponse doCall() {
|
public ExecResponse doCall() {
|
||||||
ExecResponse returnVal = super.doCall();
|
ExecResponse returnVal = super.doCall();
|
||||||
boolean complete = runScriptNotRunning.apply(new CommandUsingClient("./" + name + " status", ssh));
|
boolean complete = runScriptNotRunning.apply(new CommandUsingClient("./" + init.getInstanceName() + " status",
|
||||||
|
ssh));
|
||||||
logger.debug("<< complete(%s)", complete);
|
logger.debug("<< complete(%s)", complete);
|
||||||
if (logger.isDebugEnabled() || returnVal.getExitCode() != 0) {
|
if (logger.isDebugEnabled() || returnVal.getExitCode() != 0) {
|
||||||
logger.debug("<< stdout from %s as %s@%s\n%s", name, ssh.getUsername(), ssh.getHostAddress(), ssh.exec(
|
logger.debug("<< stdout from %s as %s@%s\n%s", init.getInstanceName(), ssh.getUsername(),
|
||||||
"./" + name + " tail").getOutput());
|
ssh.getHostAddress(), ssh.exec("./" + init.getInstanceName() + " tail").getOutput());
|
||||||
logger.debug("<< stderr from %s as %s@%s\n%s", name, ssh.getUsername(), ssh.getHostAddress(), ssh.exec(
|
logger.debug("<< stderr from %s as %s@%s\n%s", init.getInstanceName(), ssh.getUsername(),
|
||||||
"./" + name + " tailerr").getOutput());
|
ssh.getHostAddress(), ssh.exec("./" + init.getInstanceName() + " tailerr").getOutput());
|
||||||
}
|
}
|
||||||
return returnVal;
|
return returnVal;
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,7 +224,7 @@ public class BaseComputeService implements ComputeService {
|
||||||
Multimap<NodeMetadata, CustomizationResponse> customizationResponses = LinkedHashMultimap.create();
|
Multimap<NodeMetadata, CustomizationResponse> customizationResponses = LinkedHashMultimap.create();
|
||||||
|
|
||||||
if (template.getOptions().getRunScript() != null)
|
if (template.getOptions().getRunScript() != null)
|
||||||
template.getOptions().runScript(initAdminAccess.apply(template.getOptions().getRunScript()));
|
initAdminAccess.visit(template.getOptions().getRunScript());
|
||||||
|
|
||||||
Map<?, Future<Void>> responses = runNodesAndAddToSetStrategy.execute(group, count, template, goodNodes, badNodes,
|
Map<?, Future<Void>> responses = runNodesAndAddToSetStrategy.execute(group, count, template, goodNodes, badNodes,
|
||||||
customizationResponses);
|
customizationResponses);
|
||||||
|
@ -550,7 +550,7 @@ public class BaseComputeService implements ComputeService {
|
||||||
Map<NodeMetadata, Future<ExecResponse>> responses = newLinkedHashMap();
|
Map<NodeMetadata, Future<ExecResponse>> responses = newLinkedHashMap();
|
||||||
Map<?, Exception> exceptions = ImmutableMap.<Object, Exception> of();
|
Map<?, Exception> exceptions = ImmutableMap.<Object, Exception> of();
|
||||||
|
|
||||||
runScript = initAdminAccess.apply(runScript);
|
initAdminAccess.visit(runScript);
|
||||||
|
|
||||||
Iterable<? extends RunScriptOnNode> scriptRunners = transformNodesIntoInitializedScriptRunners(
|
Iterable<? extends RunScriptOnNode> scriptRunners = transformNodesIntoInitializedScriptRunners(
|
||||||
nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter), runScript, options, badNodes);
|
nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter), runScript, options, badNodes);
|
||||||
|
|
|
@ -502,7 +502,7 @@ public abstract class BaseComputeServiceLiveTest {
|
||||||
|
|
||||||
// note this is a dependency on the template resolution
|
// note this is a dependency on the template resolution
|
||||||
template.getOptions().runScript(
|
template.getOptions().runScript(
|
||||||
RunScriptData.createScriptInstallAndStartJBoss(keyPair.get("public"), template.getImage()
|
RunScriptData.createScriptInstallAndStartJBoss(template.getImage()
|
||||||
.getOperatingSystem()));
|
.getOperatingSystem()));
|
||||||
try {
|
try {
|
||||||
NodeMetadata node = getOnlyElement(client.createNodesInGroup(group, 1, template));
|
NodeMetadata node = getOnlyElement(client.createNodesInGroup(group, 1, template));
|
||||||
|
|
|
@ -30,6 +30,7 @@ import static org.jclouds.scriptbuilder.domain.Statements.switchArg;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.jclouds.scriptbuilder.domain.CreateRunScript;
|
||||||
import org.jclouds.scriptbuilder.domain.Statement;
|
import org.jclouds.scriptbuilder.domain.Statement;
|
||||||
import org.jclouds.scriptbuilder.domain.StatementList;
|
import org.jclouds.scriptbuilder.domain.StatementList;
|
||||||
|
|
||||||
|
@ -47,6 +48,8 @@ public class InitBuilder extends ScriptBuilder {
|
||||||
private final String instanceName;
|
private final String instanceName;
|
||||||
private final String instanceHome;
|
private final String instanceHome;
|
||||||
private final String logDir;
|
private final String logDir;
|
||||||
|
private final StatementList initStatement;
|
||||||
|
private final CreateRunScript createRunScript;
|
||||||
|
|
||||||
public InitBuilder(String instanceName, String instanceHome, String logDir, Map<String, String> variables,
|
public InitBuilder(String instanceName, String instanceHome, String logDir, Map<String, String> variables,
|
||||||
Iterable<Statement> statements) {
|
Iterable<Statement> statements) {
|
||||||
|
@ -55,11 +58,20 @@ public class InitBuilder extends ScriptBuilder {
|
||||||
|
|
||||||
public InitBuilder(String instanceName, String instanceHome, String logDir, Map<String, String> variables,
|
public InitBuilder(String instanceName, String instanceHome, String logDir, Map<String, String> variables,
|
||||||
Iterable<Statement> initStatements, Iterable<Statement> statements) {
|
Iterable<Statement> initStatements, Iterable<Statement> statements) {
|
||||||
|
Map<String, String> defaultVariables = ImmutableMap.of("instanceName", instanceName, "instanceHome",
|
||||||
|
instanceHome, "logDir", logDir);
|
||||||
|
this.initStatement = new StatementList(initStatements);
|
||||||
|
this.createRunScript = createRunScript(instanceName,// TODO: convert
|
||||||
|
// so
|
||||||
|
// that
|
||||||
|
// createRunScript
|
||||||
|
// can take from a
|
||||||
|
// variable
|
||||||
|
Iterables.concat(variables.keySet(), defaultVariables.keySet()), "{varl}INSTANCE_HOME{varr}", statements);
|
||||||
this.instanceName = checkNotNull(instanceName, "instanceName");
|
this.instanceName = checkNotNull(instanceName, "instanceName");
|
||||||
this.instanceHome = checkNotNull(instanceHome, "instanceHome");
|
this.instanceHome = checkNotNull(instanceHome, "instanceHome");
|
||||||
this.logDir = checkNotNull(logDir, "logDir");
|
this.logDir = checkNotNull(logDir, "logDir");
|
||||||
Map<String, String> defaultVariables = ImmutableMap.of("instanceName", instanceName, "instanceHome",
|
|
||||||
instanceHome, "logDir", logDir);
|
|
||||||
addEnvironmentVariableScope("default", defaultVariables)
|
addEnvironmentVariableScope("default", defaultVariables)
|
||||||
.addEnvironmentVariableScope(instanceName, variables)
|
.addEnvironmentVariableScope(instanceName, variables)
|
||||||
.addStatement(
|
.addStatement(
|
||||||
|
@ -68,17 +80,8 @@ public class InitBuilder extends ScriptBuilder {
|
||||||
new ImmutableMap.Builder<String, Statement>()
|
new ImmutableMap.Builder<String, Statement>()
|
||||||
.put(
|
.put(
|
||||||
"init",
|
"init",
|
||||||
newStatementList(call("default"), call(instanceName),
|
newStatementList(call("default"), call(instanceName), initStatement,
|
||||||
new StatementList(initStatements), createRunScript(
|
createRunScript))
|
||||||
instanceName,// TODO: convert
|
|
||||||
// so
|
|
||||||
// that
|
|
||||||
// createRunScript
|
|
||||||
// can take from a
|
|
||||||
// variable
|
|
||||||
Iterables.concat(variables.keySet(),
|
|
||||||
defaultVariables.keySet()),
|
|
||||||
"{varl}INSTANCE_HOME{varr}", statements)))
|
|
||||||
.put(
|
.put(
|
||||||
"status",
|
"status",
|
||||||
newStatementList(call("default"),
|
newStatementList(call("default"),
|
||||||
|
@ -165,4 +168,12 @@ public class InitBuilder extends ScriptBuilder {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[instanceName=" + instanceName + ", instanceHome=" + instanceHome + ", logDir=" + logDir + "]";
|
return "[instanceName=" + instanceName + ", instanceHome=" + instanceHome + ", logDir=" + logDir + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public StatementList getInitStatement() {
|
||||||
|
return initStatement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateRunScript getCreateRunScript() {
|
||||||
|
return createRunScript;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -24,9 +24,11 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import org.jclouds.scriptbuilder.domain.AcceptsStatementVisitor;
|
||||||
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.jclouds.scriptbuilder.domain.StatementVisitor;
|
||||||
import org.jclouds.scriptbuilder.util.Utils;
|
import org.jclouds.scriptbuilder.util.Utils;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
@ -41,7 +43,7 @@ import com.google.common.collect.Maps;
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
public class ScriptBuilder implements Statement {
|
public class ScriptBuilder implements Statement, AcceptsStatementVisitor {
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
List<Statement> statements = Lists.newArrayList();
|
List<Statement> statements = Lists.newArrayList();
|
||||||
|
@ -147,4 +149,11 @@ public class ScriptBuilder implements Statement {
|
||||||
public Iterable<String> functionDependencies(OsFamily family) {
|
public Iterable<String> functionDependencies(OsFamily family) {
|
||||||
return ImmutableSet.<String> of();
|
return ImmutableSet.<String> of();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void accept(StatementVisitor visitor) {
|
||||||
|
for (Statement statement : statements) {
|
||||||
|
visitor.visit(statement);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
|
package org.jclouds.scriptbuilder.domain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
public interface AcceptsStatementVisitor {
|
||||||
|
|
||||||
|
void accept(StatementVisitor visitor);
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
|
package org.jclouds.scriptbuilder.domain;
|
||||||
|
|
||||||
|
import org.jclouds.scriptbuilder.statements.login.AdminAccess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
public abstract class AdminAccessVisitor implements StatementVisitor {
|
||||||
|
public abstract void visit(AdminAccess input);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(Statement input) {
|
||||||
|
if (input == null)
|
||||||
|
return;
|
||||||
|
if (input instanceof AcceptsStatementVisitor) {
|
||||||
|
AcceptsStatementVisitor.class.cast(input).accept(this);
|
||||||
|
} else if (input instanceof AdminAccess) {
|
||||||
|
visit(AdminAccess.class.cast(input));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,18 +41,17 @@ import com.google.common.collect.Maps;
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
public class CreateRunScript implements Statement {
|
public class CreateRunScript extends StatementList {
|
||||||
public final static String MARKER = "END_OF_SCRIPT";
|
public final static String MARKER = "END_OF_SCRIPT";
|
||||||
final String instanceName;
|
final String instanceName;
|
||||||
final Iterable<String> exports;
|
final Iterable<String> exports;
|
||||||
final String pwd;
|
final String pwd;
|
||||||
final Iterable<Statement> statements;
|
|
||||||
|
|
||||||
public CreateRunScript(String instanceName, Iterable<String> exports, String pwd, Iterable<Statement> statements) {
|
public CreateRunScript(String instanceName, Iterable<String> exports, String pwd, Iterable<Statement> statements) {
|
||||||
|
super(statements);
|
||||||
this.instanceName = checkNotNull(instanceName, "instanceName");
|
this.instanceName = checkNotNull(instanceName, "instanceName");
|
||||||
this.exports = checkNotNull(exports, "exports");
|
this.exports = checkNotNull(exports, "exports");
|
||||||
this.pwd = checkNotNull(pwd, "pwd").replaceAll("[/\\\\]", "{fs}");
|
this.pwd = checkNotNull(pwd, "pwd").replaceAll("[/\\\\]", "{fs}");
|
||||||
this.statements = checkNotNull(statements, "statements");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class AddTitleToFile implements Statement {
|
public static class AddTitleToFile implements Statement {
|
||||||
|
|
|
@ -30,7 +30,7 @@ import com.google.common.collect.ImmutableList.Builder;
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
public class StatementList implements Statement {
|
public class StatementList implements Statement, AcceptsStatementVisitor {
|
||||||
|
|
||||||
public final List<Statement> statements;
|
public final List<Statement> statements;
|
||||||
|
|
||||||
|
@ -84,7 +84,10 @@ public class StatementList implements Statement {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Statement> getStatements() {
|
@Override
|
||||||
return statements;
|
public void accept(StatementVisitor visitor) {
|
||||||
|
for (Statement statement : statements) {
|
||||||
|
visitor.visit(statement);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
|
package org.jclouds.scriptbuilder.domain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
public interface StatementVisitor {
|
||||||
|
void visit(Statement in);
|
||||||
|
}
|
|
@ -71,7 +71,7 @@ public class Statements {
|
||||||
return new AppendFile(path, lines, marker);
|
return new AppendFile(path, lines, marker);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Statement 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
|
||||||
|
|
|
@ -38,7 +38,7 @@ import com.google.common.collect.Lists;
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
public class SwitchArg implements Statement {
|
public class SwitchArg implements Statement, AcceptsStatementVisitor {
|
||||||
|
|
||||||
private static final String INDENT = " ";
|
private static final String INDENT = " ";
|
||||||
|
|
||||||
|
@ -161,4 +161,11 @@ public class SwitchArg implements Statement {
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void accept(StatementVisitor visitor) {
|
||||||
|
for (Statement statement : valueToActions.values()) {
|
||||||
|
visitor.visit(statement);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -18,18 +18,17 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.scriptbuilder.functions;
|
package org.jclouds.scriptbuilder.functions;
|
||||||
|
|
||||||
import java.util.NoSuchElementException;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import org.jclouds.domain.Credentials;
|
import org.jclouds.domain.Credentials;
|
||||||
|
import org.jclouds.scriptbuilder.domain.AcceptsStatementVisitor;
|
||||||
import org.jclouds.scriptbuilder.domain.Statement;
|
import org.jclouds.scriptbuilder.domain.Statement;
|
||||||
import org.jclouds.scriptbuilder.domain.StatementList;
|
import org.jclouds.scriptbuilder.domain.StatementVisitor;
|
||||||
import org.jclouds.scriptbuilder.statements.login.AdminAccess;
|
import org.jclouds.scriptbuilder.statements.login.AdminAccess;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.base.Predicates;
|
|
||||||
import com.google.common.collect.Iterables;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -41,13 +40,21 @@ public enum CredentialsFromAdminAccess implements Function<Statement, Credential
|
||||||
public Credentials apply(@Nullable Statement input) {
|
public Credentials apply(@Nullable Statement input) {
|
||||||
if (input == null)
|
if (input == null)
|
||||||
return null;
|
return null;
|
||||||
if (input instanceof StatementList) {
|
if (input instanceof AcceptsStatementVisitor) {
|
||||||
try {
|
final AtomicReference<Credentials> credsHolder = new AtomicReference<Credentials>();
|
||||||
return apply(Iterables.find(StatementList.class.cast(input).getStatements(),
|
AcceptsStatementVisitor.class.cast(input).accept(new StatementVisitor() {
|
||||||
Predicates.instanceOf(AdminAccess.class)));
|
|
||||||
} catch (NoSuchElementException e) {
|
@Override
|
||||||
return null;
|
public void visit(Statement in) {
|
||||||
|
if (credsHolder.get() == null) {
|
||||||
|
Credentials creds = apply(in);
|
||||||
|
if (creds != null)
|
||||||
|
credsHolder.set(creds);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
return credsHolder.get();
|
||||||
} else if (input instanceof AdminAccess) {
|
} else if (input instanceof AdminAccess) {
|
||||||
return AdminAccess.class.cast(input).getAdminCredentials();
|
return AdminAccess.class.cast(input).getAdminCredentials();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -20,21 +20,15 @@ package org.jclouds.scriptbuilder.functions;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import org.jclouds.scriptbuilder.domain.Statement;
|
import org.jclouds.scriptbuilder.domain.AdminAccessVisitor;
|
||||||
import org.jclouds.scriptbuilder.domain.StatementList;
|
|
||||||
import org.jclouds.scriptbuilder.statements.login.AdminAccess;
|
import org.jclouds.scriptbuilder.statements.login.AdminAccess;
|
||||||
import org.jclouds.scriptbuilder.statements.login.AdminAccess.Configuration;
|
import org.jclouds.scriptbuilder.statements.login.AdminAccess.Configuration;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.google.common.collect.ImmutableList.Builder;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Statement used in a shell script
|
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
public class InitAdminAccess implements Function<Statement, Statement> {
|
public class InitAdminAccess extends AdminAccessVisitor {
|
||||||
private final AdminAccess.Configuration adminAccessConfiguration;
|
private final AdminAccess.Configuration adminAccessConfiguration;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
|
@ -43,16 +37,7 @@ public class InitAdminAccess implements Function<Statement, Statement> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Statement apply(Statement input) {
|
public void visit(AdminAccess input) {
|
||||||
if (input instanceof StatementList) {
|
input.init(adminAccessConfiguration);
|
||||||
Builder<Statement> statements = ImmutableList.<Statement> builder();
|
|
||||||
for (Statement statement : StatementList.class.cast(input).getStatements())
|
|
||||||
statements.add(apply(statement));
|
|
||||||
return new StatementList(statements.build());
|
|
||||||
} else if (input instanceof AdminAccess) {
|
|
||||||
return AdminAccess.class.cast(input).apply(adminAccessConfiguration);
|
|
||||||
} else {
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -32,7 +32,6 @@ import org.jclouds.domain.Credentials;
|
||||||
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.login.AdminAccess.Configuration;
|
|
||||||
import org.jclouds.scriptbuilder.statements.ssh.SshStatements;
|
import org.jclouds.scriptbuilder.statements.ssh.SshStatements;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
|
@ -44,27 +43,24 @@ import com.google.common.io.Files;
|
||||||
import com.google.inject.ImplementedBy;
|
import com.google.inject.ImplementedBy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controls the administrative access to a node. By default, it will perform the
|
* Controls the administrative access to a node. By default, it will perform the following:
|
||||||
* following:
|
|
||||||
*
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>setup a new admin user which folks should use as opposed to the built-in
|
* <li>setup a new admin user which folks should use as opposed to the built-in vcloud account</li>
|
||||||
* vcloud account</li>
|
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>associate a random password to account</li>
|
* <li>associate a random password to account</li>
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>securely ( use sha 512 on client side and literally rewrite the shadow
|
* <li>securely ( use sha 512 on client side and literally rewrite the shadow entry, rather than
|
||||||
* entry, rather than pass password to OS in a script )</li>
|
* pass password to OS in a script )</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* <li>associate the users' ssh public key with the account for login</li> <li>
|
* <li>associate the users' ssh public key with the account for login</li> <li>
|
||||||
* associate it with the os group wheel</li> </ul> <li>create os group wheel</li>
|
* associate it with the os group wheel</li> </ul> <li>create os group wheel</li> <li>add sudoers
|
||||||
* <li>add sudoers for nopassword access to root by group wheel</li> <li>reset
|
* for nopassword access to root by group wheel</li> <li>reset root password securely</li> <li>
|
||||||
* root password securely</li> <li>lockdown sshd_config for no root login, nor
|
* lockdown sshd_config for no root login, nor passwords allowed</li> </ul>
|
||||||
* passwords allowed</li> </ul>
|
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
public class AdminAccess implements Statement, Function<Configuration, AdminAccess> {
|
public class AdminAccess implements Statement {
|
||||||
public static AdminAccess.Builder builder() {
|
public static AdminAccess.Builder builder() {
|
||||||
return new Builder();
|
return new Builder();
|
||||||
}
|
}
|
||||||
|
@ -177,6 +173,10 @@ public class AdminAccess implements Statement, Function<Configuration, AdminAcce
|
||||||
}
|
}
|
||||||
|
|
||||||
public AdminAccess build() {
|
public AdminAccess build() {
|
||||||
|
return new AdminAccess(buildConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Config buildConfig() {
|
||||||
try {
|
try {
|
||||||
String adminPublicKey = this.adminPublicKey;
|
String adminPublicKey = this.adminPublicKey;
|
||||||
if (adminPublicKey == null && adminPublicKeyFile != null)
|
if (adminPublicKey == null && adminPublicKeyFile != null)
|
||||||
|
@ -184,8 +184,8 @@ public class AdminAccess implements Statement, Function<Configuration, AdminAcce
|
||||||
String adminPrivateKey = this.adminPrivateKey;
|
String adminPrivateKey = this.adminPrivateKey;
|
||||||
if (adminPrivateKey == null && adminPrivateKeyFile != null)
|
if (adminPrivateKey == null && adminPrivateKeyFile != null)
|
||||||
adminPrivateKey = Files.toString(adminPrivateKeyFile, UTF_8);
|
adminPrivateKey = Files.toString(adminPrivateKeyFile, UTF_8);
|
||||||
return new AdminAccess(adminUsername, adminPublicKey, adminPrivateKey, adminPassword, loginPassword,
|
return new Config(adminUsername, adminPublicKey, adminPrivateKey, adminPassword, loginPassword, lockSsh,
|
||||||
lockSsh, grantSudoToAdminUser, authorizeAdminPublicKey, installAdminPrivateKey, resetLoginPassword,
|
grantSudoToAdminUser, authorizeAdminPublicKey, installAdminPrivateKey, resetLoginPassword,
|
||||||
cryptFunction);
|
cryptFunction);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Throwables.propagate(e);
|
Throwables.propagate(e);
|
||||||
|
@ -194,6 +194,7 @@ public class AdminAccess implements Statement, Function<Configuration, AdminAcce
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static class Config {
|
||||||
private final String adminUsername;
|
private final String adminUsername;
|
||||||
private final String adminPublicKey;
|
private final String adminPublicKey;
|
||||||
private final String adminPrivateKey;
|
private final String adminPrivateKey;
|
||||||
|
@ -207,7 +208,7 @@ public class AdminAccess implements Statement, Function<Configuration, AdminAcce
|
||||||
private final Function<String, String> cryptFunction;
|
private final Function<String, String> cryptFunction;
|
||||||
private final Credentials adminCredentials;
|
private final Credentials adminCredentials;
|
||||||
|
|
||||||
protected AdminAccess(@Nullable String adminUsername, @Nullable String adminPublicKey,
|
protected Config(@Nullable String adminUsername, @Nullable String adminPublicKey,
|
||||||
@Nullable String adminPrivateKey, @Nullable String adminPassword, @Nullable String loginPassword,
|
@Nullable String adminPrivateKey, @Nullable String adminPassword, @Nullable String loginPassword,
|
||||||
boolean lockSsh, boolean grantSudoToAdminUser, boolean authorizeAdminPublicKey,
|
boolean lockSsh, boolean grantSudoToAdminUser, boolean authorizeAdminPublicKey,
|
||||||
boolean installAdminPrivateKey, boolean resetLoginPassword, Function<String, String> cryptFunction) {
|
boolean installAdminPrivateKey, boolean resetLoginPassword, Function<String, String> cryptFunction) {
|
||||||
|
@ -228,13 +229,77 @@ public class AdminAccess implements Statement, Function<Configuration, AdminAcce
|
||||||
this.adminCredentials = null;
|
this.adminCredentials = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getAdminUsername() {
|
||||||
|
return adminUsername;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAdminPublicKey() {
|
||||||
|
return adminPublicKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAdminPrivateKey() {
|
||||||
|
return adminPrivateKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAdminPassword() {
|
||||||
|
return adminPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLoginPassword() {
|
||||||
|
return loginPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldLockSsh() {
|
||||||
|
return lockSsh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldGrantSudoToAdminUser() {
|
||||||
|
return grantSudoToAdminUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldAuthorizeAdminPublicKey() {
|
||||||
|
return authorizeAdminPublicKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldInstallAdminPrivateKey() {
|
||||||
|
return installAdminPrivateKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldResetLoginPassword() {
|
||||||
|
return resetLoginPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Function<String, String> getCryptFunction() {
|
||||||
|
return cryptFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Credentials getAdminCredentials() {
|
||||||
|
return adminCredentials;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Config config;
|
||||||
|
|
||||||
|
protected AdminAccess(Config in) {
|
||||||
|
this.config = checkNotNull(in, "in");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return new credentials or null if unchanged or unavailable
|
* @return new credentials or null if unchanged or unavailable
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public Credentials getAdminCredentials() {
|
public Credentials getAdminCredentials() {
|
||||||
return adminCredentials;
|
return config.getAdminCredentials();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getAdminPassword() {
|
||||||
|
return config.getAdminPassword();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldGrantSudoToAdminUser() {
|
||||||
|
return config.shouldGrantSudoToAdminUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -242,23 +307,26 @@ public class AdminAccess implements Statement, Function<Configuration, AdminAcce
|
||||||
return ImmutableList.of();
|
return ImmutableList.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public AdminAccess init(Configuration configuration) {
|
||||||
public AdminAccess apply(Configuration configuration) {
|
|
||||||
Builder builder = AdminAccess.builder(configuration.cryptFunction());
|
Builder builder = AdminAccess.builder(configuration.cryptFunction());
|
||||||
builder.adminUsername(this.adminUsername != null ? this.adminUsername : configuration.defaultAdminUsername()
|
builder.adminUsername(config.getAdminUsername() != null ? config.getAdminUsername() : configuration
|
||||||
.get());
|
.defaultAdminUsername().get());
|
||||||
builder.adminPassword(this.adminPassword != null ? this.adminPassword : configuration.passwordGenerator().get());
|
builder.adminPassword(config.getAdminPassword() != null ? config.getAdminPassword() : configuration
|
||||||
Map<String, String> adminSshKeys = (adminPublicKey != null && adminPrivateKey != null) ? ImmutableMap.of(
|
.passwordGenerator().get());
|
||||||
"public", adminPublicKey, "private", adminPrivateKey) : configuration.defaultAdminSshKeys().get();
|
Map<String, String> adminSshKeys = (config.getAdminPublicKey() != null && config.getAdminPrivateKey() != null) ? ImmutableMap
|
||||||
|
.of("public", config.getAdminPublicKey(), "private", config.getAdminPrivateKey())
|
||||||
|
: configuration.defaultAdminSshKeys().get();
|
||||||
builder.adminPublicKey(adminSshKeys.get("public"));
|
builder.adminPublicKey(adminSshKeys.get("public"));
|
||||||
builder.adminPrivateKey(adminSshKeys.get("private"));
|
builder.adminPrivateKey(adminSshKeys.get("private"));
|
||||||
builder.loginPassword(this.loginPassword != null ? this.loginPassword : configuration.passwordGenerator().get());
|
builder.loginPassword(config.getLoginPassword() != null ? config.getLoginPassword() : configuration
|
||||||
builder.grantSudoToAdminUser(this.grantSudoToAdminUser);
|
.passwordGenerator().get());
|
||||||
builder.authorizeAdminPublicKey(this.authorizeAdminPublicKey);
|
builder.grantSudoToAdminUser(config.shouldGrantSudoToAdminUser());
|
||||||
builder.installAdminPrivateKey(this.installAdminPrivateKey);
|
builder.authorizeAdminPublicKey(config.shouldAuthorizeAdminPublicKey());
|
||||||
builder.lockSsh(this.lockSsh);
|
builder.installAdminPrivateKey(config.shouldInstallAdminPrivateKey());
|
||||||
builder.resetLoginPassword(this.resetLoginPassword);
|
builder.lockSsh(config.shouldLockSsh());
|
||||||
return builder.build();
|
builder.resetLoginPassword(config.shouldResetLoginPassword());
|
||||||
|
this.config = builder.buildConfig();
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -266,29 +334,30 @@ public class AdminAccess implements Statement, Function<Configuration, AdminAcce
|
||||||
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");
|
||||||
checkNotNull(adminUsername, "adminUsername");
|
checkNotNull(config.getAdminUsername(), "adminUsername");
|
||||||
checkNotNull(adminPassword, "adminPassword");
|
checkNotNull(config.getAdminPassword(), "adminPassword");
|
||||||
checkNotNull(adminPublicKey, "adminPublicKey");
|
checkNotNull(config.getAdminPublicKey(), "adminPublicKey");
|
||||||
checkNotNull(adminPrivateKey, "adminPrivateKey");
|
checkNotNull(config.getAdminPrivateKey(), "adminPrivateKey");
|
||||||
checkNotNull(loginPassword, "loginPassword");
|
checkNotNull(config.getLoginPassword(), "loginPassword");
|
||||||
|
|
||||||
ImmutableList.Builder<Statement> statements = ImmutableList.<Statement> builder();
|
ImmutableList.Builder<Statement> statements = ImmutableList.<Statement> builder();
|
||||||
UserAdd.Builder userBuilder = UserAdd.builder();
|
UserAdd.Builder userBuilder = UserAdd.builder();
|
||||||
userBuilder.login(adminUsername);
|
userBuilder.login(config.getAdminUsername());
|
||||||
if (authorizeAdminPublicKey)
|
if (config.shouldAuthorizeAdminPublicKey())
|
||||||
userBuilder.authorizeRSAPublicKey(adminPublicKey);
|
userBuilder.authorizeRSAPublicKey(config.getAdminPublicKey());
|
||||||
userBuilder.password(adminPassword);
|
userBuilder.password(config.getAdminPassword());
|
||||||
if (installAdminPrivateKey)
|
if (config.shouldInstallAdminPrivateKey())
|
||||||
userBuilder.installRSAPrivateKey(adminPrivateKey);
|
userBuilder.installRSAPrivateKey(config.getAdminPrivateKey());
|
||||||
if (grantSudoToAdminUser) {
|
if (config.shouldGrantSudoToAdminUser()) {
|
||||||
statements.add(SudoStatements.createWheel());
|
statements.add(SudoStatements.createWheel());
|
||||||
userBuilder.group("wheel");
|
userBuilder.group("wheel");
|
||||||
}
|
}
|
||||||
statements.add(userBuilder.build().cryptFunction(cryptFunction));
|
statements.add(userBuilder.build().cryptFunction(config.getCryptFunction()));
|
||||||
if (lockSsh)
|
if (config.shouldLockSsh())
|
||||||
statements.add(SshStatements.lockSshd());
|
statements.add(SshStatements.lockSshd());
|
||||||
if (resetLoginPassword) {
|
if (config.shouldResetLoginPassword()) {
|
||||||
statements.add(ShadowStatements.resetLoginUserPasswordTo(loginPassword).cryptFunction(cryptFunction));
|
statements.add(ShadowStatements.resetLoginUserPasswordTo(config.getLoginPassword()).cryptFunction(
|
||||||
|
config.getCryptFunction()));
|
||||||
}
|
}
|
||||||
return new StatementList(statements.build()).render(family);
|
return new StatementList(statements.build()).render(family);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,14 +22,20 @@ import static org.easymock.EasyMock.expect;
|
||||||
import static org.easymock.classextension.EasyMock.createMock;
|
import static org.easymock.classextension.EasyMock.createMock;
|
||||||
import static org.easymock.classextension.EasyMock.replay;
|
import static org.easymock.classextension.EasyMock.replay;
|
||||||
import static org.easymock.classextension.EasyMock.verify;
|
import static org.easymock.classextension.EasyMock.verify;
|
||||||
|
import static org.jclouds.scriptbuilder.domain.Statements.appendFile;
|
||||||
|
import static org.jclouds.scriptbuilder.domain.Statements.call;
|
||||||
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.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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
|
@ -81,4 +87,25 @@ public class CredentialsFromAdminAccessTest {
|
||||||
verify(statement);
|
verify(statement);
|
||||||
verify(creds);
|
verify(creds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testWhenAdminAccessInsideInitBuilder() {
|
||||||
|
AdminAccess.Configuration configuration = createMock(AdminAccess.Configuration.class);
|
||||||
|
AdminAccess statement = createMock(AdminAccess.class);
|
||||||
|
Credentials creds = createMock(Credentials.class);
|
||||||
|
|
||||||
|
expect(statement.getAdminCredentials()).andReturn(creds);
|
||||||
|
|
||||||
|
replay(configuration);
|
||||||
|
replay(statement);
|
||||||
|
replay(creds);
|
||||||
|
|
||||||
|
InitBuilder testInitBuilder = new InitBuilder("mkebsboot", "/mnt/tmp", "/mnt/tmp", ImmutableMap.of("tmpDir",
|
||||||
|
"/mnt/tmp"), ImmutableList.<Statement> of(statement));
|
||||||
|
|
||||||
|
assertEquals(CredentialsFromAdminAccess.INSTANCE.apply(testInitBuilder), creds);
|
||||||
|
|
||||||
|
verify(configuration);
|
||||||
|
verify(statement);
|
||||||
|
verify(creds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,11 +24,16 @@ import static org.easymock.classextension.EasyMock.replay;
|
||||||
import static org.easymock.classextension.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.scriptbuilder.InitBuilder;
|
||||||
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
|
@ -36,13 +41,15 @@ import org.testng.annotations.Test;
|
||||||
public class InitAdminAccessTest {
|
public class InitAdminAccessTest {
|
||||||
|
|
||||||
public void testWhenNotAdminAccess() {
|
public void testWhenNotAdminAccess() {
|
||||||
|
AdminAccess.Configuration configuration = createMock(AdminAccess.Configuration.class);
|
||||||
|
|
||||||
InitAdminAccess initAdminAccess = new InitAdminAccess(createMock(AdminAccess.Configuration.class));
|
InitAdminAccess initAdminAccess = new InitAdminAccess(configuration);
|
||||||
Statement statement = Statements.exec("echo hello");
|
replay(configuration);
|
||||||
assertEquals(initAdminAccess.apply(statement), statement);
|
|
||||||
|
|
||||||
Statement statementList = Statements.newStatementList(statement);
|
initAdminAccess.visit(Statements.exec("echo hello"));
|
||||||
assertEquals(initAdminAccess.apply(statementList), statementList);
|
|
||||||
|
initAdminAccess.visit(Statements.newStatementList(Statements.exec("echo hello")));
|
||||||
|
verify(configuration);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,14 +58,14 @@ public class InitAdminAccessTest {
|
||||||
AdminAccess statement = createMock(AdminAccess.class);
|
AdminAccess statement = createMock(AdminAccess.class);
|
||||||
AdminAccess newStatement = createMock(AdminAccess.class);
|
AdminAccess newStatement = createMock(AdminAccess.class);
|
||||||
|
|
||||||
expect(statement.apply(configuration)).andReturn(newStatement);
|
expect(statement.init(configuration)).andReturn(newStatement);
|
||||||
|
|
||||||
replay(configuration);
|
replay(configuration);
|
||||||
replay(statement);
|
replay(statement);
|
||||||
replay(newStatement);
|
replay(newStatement);
|
||||||
InitAdminAccess initAdminAccess = new InitAdminAccess(configuration);
|
InitAdminAccess initAdminAccess = new InitAdminAccess(configuration);
|
||||||
|
|
||||||
assertEquals(initAdminAccess.apply(statement), newStatement);
|
initAdminAccess.visit(statement);
|
||||||
|
|
||||||
verify(configuration);
|
verify(configuration);
|
||||||
verify(statement);
|
verify(statement);
|
||||||
|
@ -70,15 +77,38 @@ public class InitAdminAccessTest {
|
||||||
AdminAccess statement = createMock(AdminAccess.class);
|
AdminAccess statement = createMock(AdminAccess.class);
|
||||||
AdminAccess newStatement = createMock(AdminAccess.class);
|
AdminAccess newStatement = createMock(AdminAccess.class);
|
||||||
|
|
||||||
expect(statement.apply(configuration)).andReturn(newStatement);
|
expect(statement.init(configuration)).andReturn(newStatement);
|
||||||
|
|
||||||
replay(configuration);
|
replay(configuration);
|
||||||
replay(statement);
|
replay(statement);
|
||||||
replay(newStatement);
|
replay(newStatement);
|
||||||
InitAdminAccess initAdminAccess = new InitAdminAccess(configuration);
|
InitAdminAccess initAdminAccess = new InitAdminAccess(configuration);
|
||||||
|
|
||||||
assertEquals(initAdminAccess.apply(Statements.newStatementList(statement)),
|
initAdminAccess.visit(Statements.newStatementList(statement));
|
||||||
Statements.newStatementList(newStatement));
|
|
||||||
|
verify(configuration);
|
||||||
|
verify(statement);
|
||||||
|
verify(newStatement);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testWhenAdminAccessInsideInitBuilder() {
|
||||||
|
AdminAccess.Configuration configuration = createMock(AdminAccess.Configuration.class);
|
||||||
|
AdminAccess statement = createMock(AdminAccess.class);
|
||||||
|
AdminAccess newStatement = createMock(AdminAccess.class);
|
||||||
|
|
||||||
|
expect(statement.init(configuration)).andReturn(newStatement);
|
||||||
|
|
||||||
|
replay(configuration);
|
||||||
|
replay(statement);
|
||||||
|
replay(newStatement);
|
||||||
|
|
||||||
|
InitBuilder testInitBuilder = new InitBuilder("mkebsboot", "/mnt/tmp", "/mnt/tmp", ImmutableMap.of("tmpDir",
|
||||||
|
"/mnt/tmp"), ImmutableList.<Statement> of(statement));
|
||||||
|
|
||||||
|
InitAdminAccess initAdminAccess = new InitAdminAccess(configuration);
|
||||||
|
|
||||||
|
initAdminAccess.visit(testInitBuilder);
|
||||||
|
|
||||||
verify(configuration);
|
verify(configuration);
|
||||||
verify(statement);
|
verify(statement);
|
||||||
|
|
|
@ -38,7 +38,7 @@ public class AdminAccessTest {
|
||||||
public void testStandardUNIX() throws IOException {
|
public void testStandardUNIX() throws IOException {
|
||||||
TestConfiguration.INSTANCE.reset();
|
TestConfiguration.INSTANCE.reset();
|
||||||
try {
|
try {
|
||||||
assertEquals(AdminAccess.standard().apply(TestConfiguration.INSTANCE).render(OsFamily.UNIX),
|
assertEquals(AdminAccess.standard().init(TestConfiguration.INSTANCE).render(OsFamily.UNIX),
|
||||||
CharStreams.toString(Resources.newReaderSupplier(Resources.getResource("test_adminaccess_standard.sh"),
|
CharStreams.toString(Resources.newReaderSupplier(Resources.getResource("test_adminaccess_standard.sh"),
|
||||||
Charsets.UTF_8)));
|
Charsets.UTF_8)));
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -51,7 +51,7 @@ public class AdminAccessTest {
|
||||||
try {
|
try {
|
||||||
assertEquals(
|
assertEquals(
|
||||||
AdminAccess.builder().adminPassword("bar").adminPrivateKey("fooPrivateKey")
|
AdminAccess.builder().adminPassword("bar").adminPrivateKey("fooPrivateKey")
|
||||||
.adminPublicKey("fooPublicKey").adminUsername("foo").build().apply(TestConfiguration.INSTANCE)
|
.adminPublicKey("fooPublicKey").adminUsername("foo").build().init(TestConfiguration.INSTANCE)
|
||||||
.render(OsFamily.UNIX), CharStreams.toString(Resources.newReaderSupplier(
|
.render(OsFamily.UNIX), CharStreams.toString(Resources.newReaderSupplier(
|
||||||
Resources.getResource("test_adminaccess_params.sh"), Charsets.UTF_8)));
|
Resources.getResource("test_adminaccess_params.sh"), Charsets.UTF_8)));
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -65,7 +65,7 @@ public class AdminAccessTest {
|
||||||
assertEquals(
|
assertEquals(
|
||||||
AdminAccess.builder().grantSudoToAdminUser(false).authorizeAdminPublicKey(true)
|
AdminAccess.builder().grantSudoToAdminUser(false).authorizeAdminPublicKey(true)
|
||||||
.installAdminPrivateKey(true).lockSsh(false).resetLoginPassword(false).build()
|
.installAdminPrivateKey(true).lockSsh(false).resetLoginPassword(false).build()
|
||||||
.apply(TestConfiguration.INSTANCE).render(OsFamily.UNIX), CharStreams.toString(Resources
|
.init(TestConfiguration.INSTANCE).render(OsFamily.UNIX), CharStreams.toString(Resources
|
||||||
.newReaderSupplier(Resources.getResource("test_adminaccess_plainuser.sh"), Charsets.UTF_8)));
|
.newReaderSupplier(Resources.getResource("test_adminaccess_plainuser.sh"), Charsets.UTF_8)));
|
||||||
} finally {
|
} finally {
|
||||||
TestConfiguration.INSTANCE.reset();
|
TestConfiguration.INSTANCE.reset();
|
||||||
|
@ -74,6 +74,6 @@ public class AdminAccessTest {
|
||||||
|
|
||||||
@Test(expectedExceptions = UnsupportedOperationException.class)
|
@Test(expectedExceptions = UnsupportedOperationException.class)
|
||||||
public void testCreateWheelWindowsNotSupported() {
|
public void testCreateWheelWindowsNotSupported() {
|
||||||
AdminAccess.standard().apply(TestConfiguration.INSTANCE).render(OsFamily.WINDOWS);
|
AdminAccess.standard().init(TestConfiguration.INSTANCE).render(OsFamily.WINDOWS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue