mirror of https://github.com/apache/jclouds.git
Issue 728:Permission denied executing scripts
This commit is contained in:
parent
4882b23b4f
commit
e43aa90606
|
@ -0,0 +1,123 @@
|
||||||
|
/**
|
||||||
|
* 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.callables;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import javax.inject.Named;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import org.jclouds.scriptbuilder.InitBuilder;
|
||||||
|
|
||||||
|
import com.google.common.base.Supplier;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class InitScriptConfigurationForTasks {
|
||||||
|
public static final String PROPERTY_INIT_SCRIPT_PATTERN = "jclouds.compute.init-script-pattern";
|
||||||
|
|
||||||
|
public static InitScriptConfigurationForTasks create() {
|
||||||
|
return new InitScriptConfigurationForTasks();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String basedir = "/tmp";
|
||||||
|
private String initScriptPattern = basedir + "/init-%s";
|
||||||
|
private Supplier<String> suffixSupplier;
|
||||||
|
|
||||||
|
protected InitScriptConfigurationForTasks() {
|
||||||
|
appendCurrentTimeMillisToAnonymousTaskNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(optional = true)
|
||||||
|
public InitScriptConfigurationForTasks initScriptPattern(
|
||||||
|
@Named(PROPERTY_INIT_SCRIPT_PATTERN) String initScriptPattern) {
|
||||||
|
this.initScriptPattern = checkNotNull(initScriptPattern, "initScriptPattern ex. /tmp/init-%s");
|
||||||
|
this.basedir = new File(initScriptPattern).getParent();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InitScriptConfigurationForTasks appendCurrentTimeMillisToAnonymousTaskNames() {
|
||||||
|
this.suffixSupplier = new Supplier<String>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String get() {
|
||||||
|
return System.currentTimeMillis() + "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "currentTimeMillis()";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InitScriptConfigurationForTasks appendIncrementingNumberToAnonymousTaskNames() {
|
||||||
|
this.suffixSupplier = new Supplier<String>() {
|
||||||
|
private final AtomicInteger integer = new AtomicInteger();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String get() {
|
||||||
|
return integer.getAndIncrement() + "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "incrementingNumber()";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Directory where the init script is stored. the runtime directory of the process will be in
|
||||||
|
* this dir/taskName
|
||||||
|
*/
|
||||||
|
public String getBasedir() {
|
||||||
|
return basedir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the naming convention of init scripts. ex. {@code /tmp/init-%s}, noting logs are under
|
||||||
|
* the basedir/%s where %s is the taskName
|
||||||
|
* @see InitBuilder#getHomeDir
|
||||||
|
* @see InitBuilder#getLogDir
|
||||||
|
*/
|
||||||
|
public String getInitScriptPattern() {
|
||||||
|
return initScriptPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return suffix where the taskName isn't set. by default this is
|
||||||
|
* {@link System#currentTimeMillis}
|
||||||
|
* @see #appendCurrentTimeMillisToAnonymousTaskNames
|
||||||
|
* @see #appendIncrementingNumberToAnonymousTaskNames
|
||||||
|
*/
|
||||||
|
public Supplier<String> getAnonymousTaskSuffixSupplier() {
|
||||||
|
return suffixSupplier;
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,7 +44,6 @@ 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.inject.Inject;
|
|
||||||
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,38 +52,28 @@ 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 {
|
||||||
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 String initFile;
|
protected final String initFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* @return the absolute path to the file on disk relating to this task.
|
||||||
* determines the naming convention of init scripts.
|
|
||||||
*
|
|
||||||
* ex. {@code /tmp/init-%s}
|
|
||||||
*/
|
*/
|
||||||
@Inject(optional = true)
|
public String getInitFile() {
|
||||||
@Named(PROPERTY_INIT_SCRIPT_PATTERN)
|
return initFile;
|
||||||
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) {
|
InitScriptConfigurationForTasks initScriptConfiguration, @Assisted NodeMetadata node,
|
||||||
super(sshFactory, options.shouldRunAsRoot(), checkNotNull(node, "node"), init(script, options.getTaskName()));
|
@Assisted Statement script, @Assisted RunScriptOptions options) {
|
||||||
this.initFile = String.format(initScriptPattern, options.getTaskName());
|
super(sshFactory, options.shouldRunAsRoot(), checkNotNull(node, "node"),
|
||||||
}
|
checkNotNull(script, "script") instanceof InitBuilder ? InitBuilder.class.cast(script)
|
||||||
|
: createInitScript(checkNotNull(initScriptConfiguration, "initScriptConfiguration"), options
|
||||||
private static InitBuilder init(Statement script, String name) {
|
.getTaskName(), script));
|
||||||
if (name == null) {
|
this.initFile = String.format(initScriptConfiguration.getInitScriptPattern(), init.getInstanceName());
|
||||||
if (checkNotNull(script, "script") instanceof InitBuilder)
|
|
||||||
name = InitBuilder.class.cast(script).getInstanceName();
|
|
||||||
else
|
|
||||||
name = "jclouds-script-" + System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
return checkNotNull(script, "script") instanceof InitBuilder ? InitBuilder.class.cast(script) : createInitScript(
|
|
||||||
name, script);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -105,9 +94,12 @@ public class RunScriptOnNodeAsInitScriptUsingSsh extends SudoAwareInitManager im
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static InitBuilder createInitScript(String name, Statement script) {
|
public static InitBuilder createInitScript(InitScriptConfigurationForTasks config, String name, Statement script) {
|
||||||
String path = "/tmp/" + name;
|
if (name == null) {
|
||||||
return new InitBuilder(name, path, path, Collections.<String, String> emptyMap(), Collections.singleton(script));
|
name = "jclouds-script-" + config.getAnonymousTaskSuffixSupplier().get();
|
||||||
|
}
|
||||||
|
return new InitBuilder(name, config.getBasedir() + "/" + name, config.getBasedir() + "/" + name, Collections
|
||||||
|
.<String, String> emptyMap(), Collections.singleton(script));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void refreshSshIfNewAdminCredentialsConfigured(AdminAccess input) {
|
protected void refreshSshIfNewAdminCredentialsConfigured(AdminAccess input) {
|
||||||
|
|
|
@ -47,9 +47,9 @@ 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, @Assisted NodeMetadata node, @Assisted Statement script,
|
Function<NodeMetadata, SshClient> sshFactory, InitScriptConfigurationForTasks initScriptConfiguration,
|
||||||
@Assisted RunScriptOptions options) {
|
@Assisted NodeMetadata node, @Assisted Statement script, @Assisted RunScriptOptions options) {
|
||||||
super(sshFactory, node, script, options);
|
super(sshFactory, initScriptConfiguration, node, script, options);
|
||||||
this.statusFactory = checkNotNull(statusFactory, "statusFactory");
|
this.statusFactory = checkNotNull(statusFactory, "statusFactory");
|
||||||
this.timeouts = checkNotNull(timeouts, "timeouts");
|
this.timeouts = checkNotNull(timeouts, "timeouts");
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,8 +57,8 @@ public class SudoAwareInitManager {
|
||||||
InitBuilder init) {
|
InitBuilder init) {
|
||||||
this.sshFactory = checkNotNull(sshFactory, "sshFactory");
|
this.sshFactory = checkNotNull(sshFactory, "sshFactory");
|
||||||
this.runAsRoot = runAsRoot;
|
this.runAsRoot = runAsRoot;
|
||||||
this.node = node;
|
this.node = checkNotNull(node, "node");
|
||||||
this.init = init;
|
this.init = checkNotNull(init, "init");
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
/**
|
||||||
|
* 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.callable;
|
||||||
|
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
import org.jclouds.compute.callables.InitScriptConfigurationForTasks;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.inject.AbstractModule;
|
||||||
|
import com.google.inject.Guice;
|
||||||
|
import com.google.inject.name.Names;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adam Lowe
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit", singleThreaded = true, testName = "InitScriptConfigurationForTasksTest")
|
||||||
|
public class InitScriptConfigurationForTasksTest {
|
||||||
|
|
||||||
|
public void testDefaults() {
|
||||||
|
InitScriptConfigurationForTasks config = InitScriptConfigurationForTasks.create();
|
||||||
|
assertEquals(config.getAnonymousTaskSuffixSupplier().toString(), "currentTimeMillis()");
|
||||||
|
assertEquals(config.getBasedir(), "/tmp");
|
||||||
|
assertEquals(config.getInitScriptPattern(), "/tmp/init-%s");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testPatternUpdatesBasedir() {
|
||||||
|
InitScriptConfigurationForTasks config = InitScriptConfigurationForTasks.create();
|
||||||
|
config.initScriptPattern("/var/foo-init-%s");
|
||||||
|
assertEquals(config.getBasedir(), "/var");
|
||||||
|
assertEquals(config.getInitScriptPattern(), "/var/foo-init-%s");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testPatternUpdatesBasedirGuice() {
|
||||||
|
InitScriptConfigurationForTasks config = Guice.createInjector(new AbstractModule() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bindConstant().annotatedWith(Names.named(InitScriptConfigurationForTasks.PROPERTY_INIT_SCRIPT_PATTERN)).to(
|
||||||
|
"/var/foo-init-%s");
|
||||||
|
}
|
||||||
|
|
||||||
|
}).getInstance(InitScriptConfigurationForTasks.class);
|
||||||
|
config.initScriptPattern("/var/foo-init-%s");
|
||||||
|
assertEquals(config.getBasedir(), "/var");
|
||||||
|
assertEquals(config.getInitScriptPattern(), "/var/foo-init-%s");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCurrentTimeSupplier() throws InterruptedException {
|
||||||
|
InitScriptConfigurationForTasks config = InitScriptConfigurationForTasks.create();
|
||||||
|
long time1 = Long.parseLong(config.getAnonymousTaskSuffixSupplier().get());
|
||||||
|
assert time1 <= System.currentTimeMillis();
|
||||||
|
Thread.sleep(10);
|
||||||
|
long time2 = Long.parseLong(config.getAnonymousTaskSuffixSupplier().get());
|
||||||
|
assert time2 <= System.currentTimeMillis();
|
||||||
|
assert time2 > time1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIncrementingTimeSupplier() throws InterruptedException {
|
||||||
|
InitScriptConfigurationForTasks config = InitScriptConfigurationForTasks.create()
|
||||||
|
.appendIncrementingNumberToAnonymousTaskNames();
|
||||||
|
assertEquals(config.getAnonymousTaskSuffixSupplier().get(), "0");
|
||||||
|
assertEquals(config.getAnonymousTaskSuffixSupplier().get(), "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,248 @@
|
||||||
|
/**
|
||||||
|
* 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.callable;
|
||||||
|
|
||||||
|
import static org.easymock.EasyMock.createMock;
|
||||||
|
import static org.easymock.EasyMock.expect;
|
||||||
|
import static org.easymock.EasyMock.replay;
|
||||||
|
import static org.easymock.EasyMock.verify;
|
||||||
|
import static org.jclouds.scriptbuilder.domain.Statements.exec;
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
import org.jclouds.Constants;
|
||||||
|
import org.jclouds.compute.callables.BlockUntilInitScriptStatusIsZeroThenReturnOutput;
|
||||||
|
import org.jclouds.compute.callables.InitScriptConfigurationForTasks;
|
||||||
|
import org.jclouds.compute.callables.RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete;
|
||||||
|
import org.jclouds.compute.domain.ExecResponse;
|
||||||
|
import org.jclouds.compute.domain.NodeMetadata;
|
||||||
|
import org.jclouds.compute.domain.NodeMetadataBuilder;
|
||||||
|
import org.jclouds.compute.domain.NodeState;
|
||||||
|
import org.jclouds.compute.options.RunScriptOptions;
|
||||||
|
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||||
|
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
|
||||||
|
import org.jclouds.concurrent.MoreExecutors;
|
||||||
|
import org.jclouds.concurrent.config.ExecutorServiceModule;
|
||||||
|
import org.jclouds.domain.Credentials;
|
||||||
|
import org.jclouds.scriptbuilder.InitBuilder;
|
||||||
|
import org.jclouds.scriptbuilder.domain.OsFamily;
|
||||||
|
import org.jclouds.scriptbuilder.domain.Statement;
|
||||||
|
import org.jclouds.ssh.SshClient;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.base.Functions;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.inject.AbstractModule;
|
||||||
|
import com.google.inject.Guice;
|
||||||
|
import com.google.inject.assistedinject.FactoryModuleBuilder;
|
||||||
|
import com.google.inject.name.Names;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit", singleThreaded = true, testName = "RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest")
|
||||||
|
public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilCompleteTest {
|
||||||
|
|
||||||
|
BlockUntilInitScriptStatusIsZeroThenReturnOutput.Factory statusFactory = Guice.createInjector(
|
||||||
|
new ExecutorServiceModule(MoreExecutors.sameThreadExecutor(), MoreExecutors.sameThreadExecutor()),
|
||||||
|
new AbstractModule() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bindConstant().annotatedWith(Names.named(Constants.PROPERTY_USER_THREADS)).to(1);
|
||||||
|
bindConstant().annotatedWith(Names.named(Constants.PROPERTY_IO_WORKER_THREADS)).to(1);
|
||||||
|
bindConstant().annotatedWith(Names.named(ComputeServiceConstants.PROPERTY_TIMEOUT_SCRIPT_COMPLETE))
|
||||||
|
.to(100);
|
||||||
|
install(new FactoryModuleBuilder()
|
||||||
|
.build(BlockUntilInitScriptStatusIsZeroThenReturnOutput.Factory.class));
|
||||||
|
}
|
||||||
|
}).getInstance(BlockUntilInitScriptStatusIsZeroThenReturnOutput.Factory.class);
|
||||||
|
|
||||||
|
// fail faster than normal
|
||||||
|
Timeouts timeouts = Guice.createInjector(new AbstractModule() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bindConstant().annotatedWith(Names.named(ComputeServiceConstants.PROPERTY_TIMEOUT_SCRIPT_COMPLETE)).to(100l);
|
||||||
|
}
|
||||||
|
}).getInstance(Timeouts.class);
|
||||||
|
|
||||||
|
@Test(expectedExceptions = IllegalStateException.class)
|
||||||
|
public void testWithoutInitThrowsIllegalStateException() {
|
||||||
|
Statement command = exec("doFoo");
|
||||||
|
NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.RUNNING).credentials(
|
||||||
|
new Credentials("tester", "notalot")).build();
|
||||||
|
|
||||||
|
SshClient sshClient = createMock(SshClient.class);
|
||||||
|
|
||||||
|
replay(sshClient);
|
||||||
|
|
||||||
|
RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete(
|
||||||
|
statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)),
|
||||||
|
InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command,
|
||||||
|
new RunScriptOptions());
|
||||||
|
|
||||||
|
testMe.call();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDefault() {
|
||||||
|
Statement command = exec("doFoo");
|
||||||
|
NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.RUNNING).credentials(
|
||||||
|
new Credentials("tester", "notalot")).build();
|
||||||
|
|
||||||
|
SshClient sshClient = createMock(SshClient.class);
|
||||||
|
|
||||||
|
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0",
|
||||||
|
ImmutableMap.<String, String> of(), ImmutableSet.of(command));
|
||||||
|
|
||||||
|
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("./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
|
||||||
|
expect(sshClient.exec("sudo ./jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0));
|
||||||
|
|
||||||
|
// signal the command completed
|
||||||
|
expect(sshClient.exec("./jclouds-script-0 status")).andReturn(new ExecResponse("", "", 1));
|
||||||
|
expect(sshClient.exec("./jclouds-script-0 tail")).andReturn(new ExecResponse("out", "", 0));
|
||||||
|
expect(sshClient.exec("./jclouds-script-0 tailerr")).andReturn(new ExecResponse("err", "", 0));
|
||||||
|
|
||||||
|
sshClient.disconnect();
|
||||||
|
replay(sshClient);
|
||||||
|
|
||||||
|
RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete(
|
||||||
|
statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)),
|
||||||
|
InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command,
|
||||||
|
new RunScriptOptions());
|
||||||
|
|
||||||
|
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", 0));
|
||||||
|
|
||||||
|
verify(sshClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWithSudoPassword() {
|
||||||
|
Statement command = exec("doFoo");
|
||||||
|
NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.RUNNING).credentials(
|
||||||
|
new Credentials("tester", "notalot")).adminPassword("rootme").build();
|
||||||
|
|
||||||
|
SshClient sshClient = createMock(SshClient.class);
|
||||||
|
|
||||||
|
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0",
|
||||||
|
ImmutableMap.<String, String> of(), ImmutableSet.of(command));
|
||||||
|
|
||||||
|
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("./jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0));
|
||||||
|
|
||||||
|
// since there's an adminPassword we must pass this in
|
||||||
|
expect(sshClient.exec("echo 'rootme'|sudo -S ./jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0));
|
||||||
|
|
||||||
|
// signal the command completed
|
||||||
|
expect(sshClient.exec("./jclouds-script-0 status")).andReturn(new ExecResponse("", "", 1));
|
||||||
|
expect(sshClient.exec("./jclouds-script-0 tail")).andReturn(new ExecResponse("out", "", 0));
|
||||||
|
expect(sshClient.exec("./jclouds-script-0 tailerr")).andReturn(new ExecResponse("err", "", 0));
|
||||||
|
|
||||||
|
sshClient.disconnect();
|
||||||
|
replay(sshClient);
|
||||||
|
|
||||||
|
RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete(
|
||||||
|
statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)),
|
||||||
|
InitScriptConfigurationForTasks.create().appendIncrementingNumberToAnonymousTaskNames(), node, command,
|
||||||
|
new RunScriptOptions());
|
||||||
|
|
||||||
|
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", 0));
|
||||||
|
|
||||||
|
verify(sshClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNotRoot() {
|
||||||
|
Statement command = exec("doFoo");
|
||||||
|
NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.RUNNING).credentials(
|
||||||
|
new Credentials("tester", "notalot")).adminPassword("rootme").build();
|
||||||
|
|
||||||
|
SshClient sshClient = createMock(SshClient.class);
|
||||||
|
|
||||||
|
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0",
|
||||||
|
ImmutableMap.<String, String> of(), ImmutableSet.of(command));
|
||||||
|
|
||||||
|
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("./jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0));
|
||||||
|
|
||||||
|
// kick off as current user
|
||||||
|
expect(sshClient.exec("./jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0));
|
||||||
|
|
||||||
|
// signal the command completed
|
||||||
|
expect(sshClient.exec("./jclouds-script-0 status")).andReturn(new ExecResponse("", "", 1));
|
||||||
|
expect(sshClient.exec("./jclouds-script-0 tail")).andReturn(new ExecResponse("out", "", 0));
|
||||||
|
expect(sshClient.exec("./jclouds-script-0 tailerr")).andReturn(new ExecResponse("err", "", 0));
|
||||||
|
|
||||||
|
sshClient.disconnect();
|
||||||
|
replay(sshClient);
|
||||||
|
|
||||||
|
RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete testMe = new RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete(
|
||||||
|
statusFactory, timeouts, Functions.forMap(ImmutableMap.of(node, sshClient)),
|
||||||
|
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", 0));
|
||||||
|
|
||||||
|
verify(sshClient);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,190 @@
|
||||||
|
/**
|
||||||
|
* 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.callable;
|
||||||
|
|
||||||
|
import static org.easymock.EasyMock.createMock;
|
||||||
|
import static org.easymock.EasyMock.expect;
|
||||||
|
import static org.easymock.EasyMock.replay;
|
||||||
|
import static org.easymock.EasyMock.verify;
|
||||||
|
import static org.jclouds.scriptbuilder.domain.Statements.exec;
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
import org.jclouds.compute.callables.InitScriptConfigurationForTasks;
|
||||||
|
import org.jclouds.compute.callables.RunScriptOnNodeAsInitScriptUsingSsh;
|
||||||
|
import org.jclouds.compute.domain.ExecResponse;
|
||||||
|
import org.jclouds.compute.domain.NodeMetadata;
|
||||||
|
import org.jclouds.compute.domain.NodeMetadataBuilder;
|
||||||
|
import org.jclouds.compute.domain.NodeState;
|
||||||
|
import org.jclouds.compute.options.RunScriptOptions;
|
||||||
|
import org.jclouds.domain.Credentials;
|
||||||
|
import org.jclouds.scriptbuilder.InitBuilder;
|
||||||
|
import org.jclouds.scriptbuilder.domain.OsFamily;
|
||||||
|
import org.jclouds.scriptbuilder.domain.Statement;
|
||||||
|
import org.jclouds.ssh.SshClient;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.base.Functions;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit", singleThreaded = true, testName = "RunScriptOnNodeAsInitScriptUsingSshTest")
|
||||||
|
public class RunScriptOnNodeAsInitScriptUsingSshTest {
|
||||||
|
|
||||||
|
@Test(expectedExceptions = IllegalStateException.class)
|
||||||
|
public void testWithoutInitThrowsIllegalStateException() {
|
||||||
|
Statement command = exec("doFoo");
|
||||||
|
NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.RUNNING).credentials(
|
||||||
|
new Credentials("tester", "notalot")).build();
|
||||||
|
|
||||||
|
SshClient sshClient = createMock(SshClient.class);
|
||||||
|
|
||||||
|
replay(sshClient);
|
||||||
|
|
||||||
|
RunScriptOnNodeAsInitScriptUsingSsh testMe = new RunScriptOnNodeAsInitScriptUsingSsh(Functions
|
||||||
|
.forMap(ImmutableMap.of(node, sshClient)), InitScriptConfigurationForTasks.create()
|
||||||
|
.appendIncrementingNumberToAnonymousTaskNames(), node, command, new RunScriptOptions());
|
||||||
|
|
||||||
|
testMe.call();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDefault() {
|
||||||
|
Statement command = exec("doFoo");
|
||||||
|
NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.RUNNING).credentials(
|
||||||
|
new Credentials("tester", "notalot")).build();
|
||||||
|
|
||||||
|
SshClient sshClient = createMock(SshClient.class);
|
||||||
|
|
||||||
|
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0",
|
||||||
|
ImmutableMap.<String, String> of(), ImmutableSet.of(command));
|
||||||
|
|
||||||
|
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("./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
|
||||||
|
expect(sshClient.exec("sudo ./jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0));
|
||||||
|
|
||||||
|
|
||||||
|
sshClient.disconnect();
|
||||||
|
replay(sshClient);
|
||||||
|
|
||||||
|
RunScriptOnNodeAsInitScriptUsingSsh testMe = new RunScriptOnNodeAsInitScriptUsingSsh(Functions
|
||||||
|
.forMap(ImmutableMap.of(node, sshClient)), InitScriptConfigurationForTasks.create()
|
||||||
|
.appendIncrementingNumberToAnonymousTaskNames(), node, command, new RunScriptOptions());
|
||||||
|
|
||||||
|
assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0");
|
||||||
|
assertEquals(testMe.getNode(), node);
|
||||||
|
assertEquals(testMe.getStatement(), init);
|
||||||
|
|
||||||
|
testMe.init();
|
||||||
|
testMe.call();
|
||||||
|
verify(sshClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testWithSudoPassword() {
|
||||||
|
Statement command = exec("doFoo");
|
||||||
|
NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.RUNNING).credentials(
|
||||||
|
new Credentials("tester", "notalot")).adminPassword("rootme").build();
|
||||||
|
|
||||||
|
SshClient sshClient = createMock(SshClient.class);
|
||||||
|
|
||||||
|
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0",
|
||||||
|
ImmutableMap.<String, String> of(), ImmutableSet.of(command));
|
||||||
|
|
||||||
|
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("./jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0));
|
||||||
|
|
||||||
|
// since there's an adminPassword we must pass this in
|
||||||
|
expect(sshClient.exec("echo 'rootme'|sudo -S ./jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0));
|
||||||
|
|
||||||
|
|
||||||
|
sshClient.disconnect();
|
||||||
|
replay(sshClient);
|
||||||
|
|
||||||
|
RunScriptOnNodeAsInitScriptUsingSsh testMe = new RunScriptOnNodeAsInitScriptUsingSsh(Functions
|
||||||
|
.forMap(ImmutableMap.of(node, sshClient)), InitScriptConfigurationForTasks.create()
|
||||||
|
.appendIncrementingNumberToAnonymousTaskNames(), node, command, new RunScriptOptions());
|
||||||
|
|
||||||
|
assertEquals(testMe.getInitFile(), "/tmp/init-jclouds-script-0");
|
||||||
|
assertEquals(testMe.getNode(), node);
|
||||||
|
assertEquals(testMe.getStatement(), init);
|
||||||
|
|
||||||
|
testMe.init();
|
||||||
|
testMe.call();
|
||||||
|
verify(sshClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void testNotRoot() {
|
||||||
|
Statement command = exec("doFoo");
|
||||||
|
NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.RUNNING).credentials(
|
||||||
|
new Credentials("tester", "notalot")).adminPassword("rootme").build();
|
||||||
|
|
||||||
|
SshClient sshClient = createMock(SshClient.class);
|
||||||
|
|
||||||
|
InitBuilder init = new InitBuilder("jclouds-script-0", "/tmp/jclouds-script-0", "/tmp/jclouds-script-0",
|
||||||
|
ImmutableMap.<String, String> of(), ImmutableSet.of(command));
|
||||||
|
|
||||||
|
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("./jclouds-script-0 init")).andReturn(new ExecResponse("", "", 0));
|
||||||
|
|
||||||
|
// kick off as current user
|
||||||
|
expect(sshClient.exec("./jclouds-script-0 start")).andReturn(new ExecResponse("", "", 0));
|
||||||
|
|
||||||
|
sshClient.disconnect();
|
||||||
|
replay(sshClient);
|
||||||
|
|
||||||
|
RunScriptOnNodeAsInitScriptUsingSsh testMe = new RunScriptOnNodeAsInitScriptUsingSsh(Functions
|
||||||
|
.forMap(ImmutableMap.of(node, sshClient)), 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();
|
||||||
|
testMe.call();
|
||||||
|
verify(sshClient);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue