blob: bd4496b2197edd7460b5594bb07c6b3fe28016cb [file] [log] [blame]
/**
* 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.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.and;
import static com.google.common.base.Predicates.not;
import static com.google.common.base.Predicates.notNull;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Maps.newLinkedHashMap;
import static com.google.common.collect.Sets.filter;
import static com.google.common.collect.Sets.newLinkedHashSet;
import static com.google.common.util.concurrent.Futures.immediateFuture;
import static org.jclouds.compute.predicates.NodePredicates.TERMINATED;
import static org.jclouds.compute.predicates.NodePredicates.all;
import static org.jclouds.concurrent.FutureIterables.awaitCompletion;
import static org.jclouds.concurrent.FutureIterables.transformParallel;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.RunScriptOnNodesException;
import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
import org.jclouds.compute.strategy.CreateNodesInGroupThenAddToSet;
import org.jclouds.compute.strategy.DestroyNodeStrategy;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import org.jclouds.compute.strategy.InitializeRunScriptOnNodeOrPlaceInBadMap;
import org.jclouds.compute.strategy.ListNodesStrategy;
import org.jclouds.compute.strategy.RebootNodeStrategy;
import org.jclouds.compute.strategy.ResumeNodeStrategy;
import org.jclouds.compute.strategy.RunScriptOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import org.jclouds.compute.strategy.SuspendNodeStrategy;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.domain.LoginCredentials.Builder;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.logging.Logger;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.scriptbuilder.functions.InitAdminAccess;
import org.jclouds.util.Maps2;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.util.concurrent.ListenableFuture;
/**
*
* @author Adrian Cole
*/
@Singleton
public class BaseComputeService implements ComputeService {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
protected final ComputeServiceContext context;
protected final Map<String, Credentials> credentialStore;
private final Supplier<Set<? extends Image>> images;
private final Supplier<Set<? extends Hardware>> hardwareProfiles;
private final Supplier<Set<? extends Location>> locations;
private final ListNodesStrategy listNodesStrategy;
private final GetNodeMetadataStrategy getNodeMetadataStrategy;
private final CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy;
private final RebootNodeStrategy rebootNodeStrategy;
private final DestroyNodeStrategy destroyNodeStrategy;
private final ResumeNodeStrategy resumeNodeStrategy;
private final SuspendNodeStrategy suspendNodeStrategy;
private final Provider<TemplateBuilder> templateBuilderProvider;
private final Provider<TemplateOptions> templateOptionsProvider;
private final Predicate<AtomicReference<NodeMetadata>> nodeRunning;
private final Predicate<AtomicReference<NodeMetadata>> nodeTerminated;
private final Predicate<AtomicReference<NodeMetadata>> nodeSuspended;
private final InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory;
private final Timeouts timeouts;
private final InitAdminAccess initAdminAccess;
private final PersistNodeCredentials persistNodeCredentials;
private final RunScriptOnNode.Factory runScriptOnNodeFactory;
private final ExecutorService executor;
@Inject
protected BaseComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore,
@Memoized Supplier<Set<? extends Image>> images, @Memoized Supplier<Set<? extends Hardware>> hardwareProfiles,
@Memoized Supplier<Set<? extends Location>> locations, ListNodesStrategy listNodesStrategy,
GetNodeMetadataStrategy getNodeMetadataStrategy, CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy,
RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy,
ResumeNodeStrategy resumeNodeStrategy, SuspendNodeStrategy suspendNodeStrategy,
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider,
@Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning,
@Named("NODE_TERMINATED") Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
@Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess,
RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials,
Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
this.context = checkNotNull(context, "context");
this.credentialStore = checkNotNull(credentialStore, "credentialStore");
this.images = checkNotNull(images, "images");
this.hardwareProfiles = checkNotNull(hardwareProfiles, "hardwareProfiles");
this.locations = checkNotNull(locations, "locations");
this.listNodesStrategy = checkNotNull(listNodesStrategy, "listNodesStrategy");
this.getNodeMetadataStrategy = checkNotNull(getNodeMetadataStrategy, "getNodeMetadataStrategy");
this.runNodesAndAddToSetStrategy = checkNotNull(runNodesAndAddToSetStrategy, "runNodesAndAddToSetStrategy");
this.rebootNodeStrategy = checkNotNull(rebootNodeStrategy, "rebootNodeStrategy");
this.resumeNodeStrategy = checkNotNull(resumeNodeStrategy, "resumeNodeStrategy");
this.suspendNodeStrategy = checkNotNull(suspendNodeStrategy, "suspendNodeStrategy");
this.destroyNodeStrategy = checkNotNull(destroyNodeStrategy, "destroyNodeStrategy");
this.templateBuilderProvider = checkNotNull(templateBuilderProvider, "templateBuilderProvider");
this.templateOptionsProvider = checkNotNull(templateOptionsProvider, "templateOptionsProvider");
this.nodeRunning = checkNotNull(nodeRunning, "nodeRunning");
this.nodeTerminated = checkNotNull(nodeTerminated, "nodeTerminated");
this.nodeSuspended = checkNotNull(nodeSuspended, "nodeSuspended");
this.initScriptRunnerFactory = checkNotNull(initScriptRunnerFactory, "initScriptRunnerFactory");
this.timeouts = checkNotNull(timeouts, "timeouts");
this.initAdminAccess = checkNotNull(initAdminAccess, "initAdminAccess");
this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory, "runScriptOnNodeFactory");
this.persistNodeCredentials = checkNotNull(persistNodeCredentials, "persistNodeCredentials");
this.executor = checkNotNull(executor, "executor");
}
/**
* {@inheritDoc}
*/
@Override
public ComputeServiceContext getContext() {
return context;
}
@Override
public Set<? extends NodeMetadata> createNodesInGroup(String group, int count, Template template)
throws RunNodesException {
checkNotNull(group, "group cannot be null");
checkNotNull(template.getLocation(), "location");
logger.debug(">> running %d node%s group(%s) location(%s) image(%s) hardwareProfile(%s) options(%s)", count,
count > 1 ? "s" : "", group, template.getLocation().getId(), template.getImage().getId(), template
.getHardware().getId(), template.getOptions());
Set<NodeMetadata> goodNodes = newLinkedHashSet();
Map<NodeMetadata, Exception> badNodes = newLinkedHashMap();
Multimap<NodeMetadata, CustomizationResponse> customizationResponses = LinkedHashMultimap.create();
if (template.getOptions().getRunScript() != null)
initAdminAccess.visit(template.getOptions().getRunScript());
Map<?, Future<Void>> responses = runNodesAndAddToSetStrategy.execute(group, count, template, goodNodes, badNodes,
customizationResponses);
Map<?, Exception> executionExceptions = awaitCompletion(responses, executor, null, logger, "createNodesInGroup("
+ group + ")");
Function<NodeMetadata, NodeMetadata> fn = persistNodeCredentials.always(template.getOptions().getRunScript());
badNodes = Maps2.transformKeys(badNodes, fn);
goodNodes = ImmutableSet.copyOf(Iterables.transform(goodNodes, fn));
if (executionExceptions.size() > 0 || badNodes.size() > 0) {
throw new RunNodesException(group, count, template, goodNodes, executionExceptions, badNodes);
}
return goodNodes;
}
@Override
public Set<? extends NodeMetadata> createNodesInGroup(String group, int count, TemplateOptions templateOptions)
throws RunNodesException {
return createNodesInGroup(group, count, templateBuilder().any().options(templateOptions).build());
}
@Override
public Set<? extends NodeMetadata> createNodesInGroup(String group, int count) throws RunNodesException {
return createNodesInGroup(group, count, templateOptions());
}
/**
* {@inheritDoc}
*/
@Override
public void destroyNode(String id) {
NodeMetadata destroyedNodeOrNull = doDestroyNode(id);
if (destroyedNodeOrNull != null)
cleanUpIncidentalResourcesOfDeadNodes(ImmutableSet.of(destroyedNodeOrNull));
}
/**
* {@inheritDoc}
*/
@Override
public Set<? extends NodeMetadata> destroyNodesMatching(Predicate<NodeMetadata> filter) {
logger.debug(">> destroying nodes matching(%s)", filter);
Set<NodeMetadata> set = newLinkedHashSet(filter(transformParallel(nodesMatchingFilterAndNotTerminated(filter),
new Function<NodeMetadata, Future<NodeMetadata>>() {
// TODO make an async interface instead of re-wrapping
@Override
public Future<NodeMetadata> apply(final NodeMetadata from) {
return executor.submit(new Callable<NodeMetadata>() {
@Nullable
@Override
public NodeMetadata call() throws Exception {
doDestroyNode(from.getId());
return from;
}
@Override
public String toString() {
return "destroyNode(" + from.getId() + ")";
}
});
}
}, executor, null, logger, "destroyNodesMatching(" + filter + ")"), notNull()));
logger.debug("<< destroyed(%d)", set.size());
cleanUpIncidentalResourcesOfDeadNodes(set);
return set;
}
/**
*
* @param id
* @return node that was deleted or null if it wasn't found
*/
@Nullable
protected NodeMetadata doDestroyNode(final String id) {
checkNotNull(id, "id");
logger.debug(">> destroying node(%s)", id);
final AtomicReference<NodeMetadata> node = new AtomicReference<NodeMetadata>();
RetryablePredicate<String> tester = new RetryablePredicate<String>(new Predicate<String>() {
@Override
public boolean apply(String input) {
try {
NodeMetadata md = destroyNodeStrategy.destroyNode(id);
if (md != null)
node.set(md);
return true;
} catch (IllegalStateException e) {
logger.warn("<< illegal state destroying node(%s)", id);
return false;
}
}
}, timeouts.nodeRunning, 1000, TimeUnit.MILLISECONDS);
boolean successful = tester.apply(id) && (node.get() == null || nodeTerminated.apply(node));
if (successful)
credentialStore.remove("node#" + id);
logger.debug("<< destroyed node(%s) success(%s)", id, successful);
return node.get();
}
protected void cleanUpIncidentalResourcesOfDeadNodes(Set<? extends NodeMetadata> deadNodes) {
// no-op; to be overridden
}
Iterable<? extends NodeMetadata> nodesMatchingFilterAndNotTerminated(Predicate<NodeMetadata> filter) {
return filter(detailsOnAllNodes(), and(checkNotNull(filter, "filter"), not(TERMINATED)));
}
/**
* @throws NoSuchElementException
* if none found
*/
Iterable<? extends NodeMetadata> nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(
Predicate<NodeMetadata> filter) {
Iterable<? extends NodeMetadata> nodes = nodesMatchingFilterAndNotTerminated(filter);
if (Iterables.size(nodes) == 0)
throw new NoSuchElementException("no nodes matched filter: " + filter);
return nodes;
}
/**
* {@inheritDoc}
*/
@Override
public Set<ComputeMetadata> listNodes() {
logger.debug(">> listing nodes");
Set<ComputeMetadata> set = newLinkedHashSet(listNodesStrategy.listNodes());
logger.debug("<< list(%d)", set.size());
return set;
}
/**
* {@inheritDoc}
*/
@Override
public Set<? extends NodeMetadata> listNodesDetailsMatching(Predicate<ComputeMetadata> filter) {
checkNotNull(filter, "filter");
logger.debug(">> listing node details matching(%s)", filter);
Set<NodeMetadata> set = newLinkedHashSet(listNodesStrategy.listDetailsOnNodesMatching(filter));
logger.debug("<< list(%d)", set.size());
return set;
}
/**
* {@inheritDoc}
*/
@Override
public Set<? extends Hardware> listHardwareProfiles() {
return hardwareProfiles.get();
}
/**
* {@inheritDoc}
*/
@Override
public Set<? extends Image> listImages() {
return images.get();
}
/**
* {@inheritDoc}
*/
@Override
public Set<? extends Location> listAssignableLocations() {
return locations.get();
}
/**
* {@inheritDoc}
*/
@Override
public TemplateBuilder templateBuilder() {
return templateBuilderProvider.get();
}
/**
* {@inheritDoc}
*/
@Override
public NodeMetadata getNodeMetadata(String id) {
checkNotNull(id, "id");
return getNodeMetadataStrategy.getNode(id);
}
/**
* {@inheritDoc}
*/
@Override
public void rebootNode(String id) {
checkNotNull(id, "id");
logger.debug(">> rebooting node(%s)", id);
AtomicReference<NodeMetadata> node = new AtomicReference<NodeMetadata>(rebootNodeStrategy.rebootNode(id));
boolean successful = nodeRunning.apply(node);
logger.debug("<< rebooted node(%s) success(%s)", id, successful);
}
/**
* {@inheritDoc}
*/
@Override
public void rebootNodesMatching(Predicate<NodeMetadata> filter) {
logger.debug(">> rebooting nodes matching(%s)", filter);
transformParallel(nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter),
new Function<NodeMetadata, Future<Void>>() {
// TODO use native async
@Override
public Future<Void> apply(NodeMetadata from) {
rebootNode(from.getId());
return immediateFuture(null);
}
}, executor, null, logger, "rebootNodesMatching(" + filter + ")");
logger.debug("<< rebooted");
}
/**
* {@inheritDoc}
*/
@Override
public void resumeNode(String id) {
checkNotNull(id, "id");
logger.debug(">> resuming node(%s)", id);
AtomicReference<NodeMetadata> node = new AtomicReference<NodeMetadata>(resumeNodeStrategy.resumeNode(id));
boolean successful = nodeRunning.apply(node);
logger.debug("<< resumed node(%s) success(%s)", id, successful);
}
/**
* {@inheritDoc}
*/
@Override
public void resumeNodesMatching(Predicate<NodeMetadata> filter) {
logger.debug(">> resuming nodes matching(%s)", filter);
transformParallel(nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter),
new Function<NodeMetadata, Future<Void>>() {
// TODO use native async
@Override
public Future<Void> apply(NodeMetadata from) {
resumeNode(from.getId());
return immediateFuture(null);
}
}, executor, null, logger, "resumeNodesMatching(" + filter + ")");
logger.debug("<< resumed");
}
/**
* {@inheritDoc}
*/
@Override
public void suspendNode(String id) {
checkNotNull(id, "id");
logger.debug(">> suspending node(%s)", id);
AtomicReference<NodeMetadata> node = new AtomicReference<NodeMetadata>(suspendNodeStrategy.suspendNode(id));
boolean successful = nodeSuspended.apply(node);
logger.debug("<< suspended node(%s) success(%s)", id, successful);
}
/**
* {@inheritDoc}
*/
@Override
public void suspendNodesMatching(Predicate<NodeMetadata> filter) {
logger.debug(">> suspending nodes matching(%s)", filter);
transformParallel(nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter),
new Function<NodeMetadata, Future<Void>>() {
// TODO use native async
@Override
public Future<Void> apply(NodeMetadata from) {
suspendNode(from.getId());
return immediateFuture(null);
}
}, executor, null, logger, "suspendNodesMatching(" + filter + ")");
logger.debug("<< suspended");
}
/**
* {@inheritDoc}
*/
@Override
public Map<NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter, String runScript)
throws RunScriptOnNodesException {
return runScriptOnNodesMatching(filter, Statements.exec(checkNotNull(runScript, "runScript")));
}
/**
* {@inheritDoc}
*/
@Override
public Map<NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter, Statement runScript)
throws RunScriptOnNodesException {
return runScriptOnNodesMatching(filter, runScript, RunScriptOptions.NONE);
}
@Override
public Map<? extends NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter,
String runScript, RunScriptOptions options) throws RunScriptOnNodesException {
return runScriptOnNodesMatching(filter, Statements.exec(checkNotNull(runScript, "runScript")), options);
}
/**
* {@inheritDoc}
*/
@Override
public Map<NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter, Statement runScript,
RunScriptOptions options) throws RunScriptOnNodesException {
checkNotNull(filter, "filter");
checkNotNull(runScript, "runScript");
checkNotNull(options, "options");
Map<NodeMetadata, ExecResponse> goodNodes = newLinkedHashMap();
Map<NodeMetadata, Exception> badNodes = newLinkedHashMap();
Map<NodeMetadata, Future<ExecResponse>> responses = newLinkedHashMap();
Map<?, Exception> exceptions = ImmutableMap.<Object, Exception> of();
initAdminAccess.visit(runScript);
Iterable<? extends RunScriptOnNode> scriptRunners = transformNodesIntoInitializedScriptRunners(
nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter), runScript, options, badNodes);
if (Iterables.size(scriptRunners) > 0) {
for (RunScriptOnNode runner : scriptRunners) {
responses.put(runner.getNode(), executor.submit(new RunScriptOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap(
runner, goodNodes, badNodes)));
}
exceptions = awaitCompletion(responses, executor, null, logger, "runScriptOnNodesMatching(" + filter + ")");
}
Function<NodeMetadata, NodeMetadata> fn = persistNodeCredentials.ifAdminAccess(runScript);
badNodes = Maps2.transformKeys(badNodes, fn);
goodNodes = Maps2.transformKeys(goodNodes, fn);
if (exceptions.size() > 0 || badNodes.size() > 0) {
throw new RunScriptOnNodesException(runScript, options, goodNodes, exceptions, badNodes);
}
return goodNodes;
}
/**
* {@inheritDoc}
*/
@Override
public ExecResponse runScriptOnNode(String id, String runScript) {
return runScriptOnNode(id, runScript, RunScriptOptions.NONE);
}
/**
* {@inheritDoc}
*/
@Override
public ExecResponse runScriptOnNode(String id, String runScript, RunScriptOptions options) {
return runScriptOnNode(id, Statements.exec(checkNotNull(runScript, "runScript")), options);
}
/**
* {@inheritDoc}
*/
@Override
public ExecResponse runScriptOnNode(String id, Statement runScript) {
return runScriptOnNode(id, runScript, RunScriptOptions.NONE);
}
/**
* {@inheritDoc}
*/
@Override
public ExecResponse runScriptOnNode(String id, Statement runScript, RunScriptOptions options) {
NodeMetadata node = this.getNodeMetadata(id);
if (node == null)
throw new NoSuchElementException(id);
if (node.getState() != NodeState.RUNNING)
throw new IllegalStateException("node " + id
+ " needs to be running before executing a script on it. current state: " + node.getState());
initAdminAccess.visit(runScript);
node = updateNodeWithCredentialsIfPresent(node, options);
ExecResponse response = runScriptOnNodeFactory.create(node, runScript, options).init().call();
persistNodeCredentials.ifAdminAccess(runScript).apply(node);
return response;
}
/**
* {@inheritDoc}
*/
@Override
public ListenableFuture<ExecResponse> submitScriptOnNode(String id, final Statement runScript,
RunScriptOptions options) {
NodeMetadata node = this.getNodeMetadata(id);
if (node == null)
throw new NoSuchElementException(id);
if (node.getState() != NodeState.RUNNING)
throw new IllegalStateException("node " + id
+ " needs to be running before executing a script on it. current state: " + node.getState());
initAdminAccess.visit(runScript);
final NodeMetadata node1 = updateNodeWithCredentialsIfPresent(node, options);
ListenableFuture<ExecResponse> response = runScriptOnNodeFactory.submit(node1, runScript, options);
response.addListener(new Runnable() {
@Override
public void run() {
persistNodeCredentials.ifAdminAccess(runScript).apply(node1);
}
}, executor);
return response;
}
private Iterable<? extends RunScriptOnNode> transformNodesIntoInitializedScriptRunners(
Iterable<? extends NodeMetadata> nodes, Statement script, RunScriptOptions options,
Map<NodeMetadata, Exception> badNodes) {
return filter(
transformParallel(nodes, new TransformNodesIntoInitializedScriptRunners(script, options, badNodes),
executor, null, logger, "initialize script runners"), notNull());
}
private Set<? extends NodeMetadata> detailsOnAllNodes() {
return newLinkedHashSet(listNodesStrategy.listDetailsOnNodesMatching(all()));
}
@Override
public TemplateOptions templateOptions() {
return templateOptionsProvider.get();
}
protected NodeMetadata updateNodeWithCredentialsIfPresent(NodeMetadata node, RunScriptOptions options) {
checkNotNull(node, "node");
Builder builder = LoginCredentials.builder(node.getCredentials());
if (options.getLoginUser() != null)
builder.user(options.getLoginUser());
if (options.hasLoginPasswordOption()) {
if (options.hasLoginPassword()) {
builder.password(options.getLoginPassword());
} else {
builder.noPassword();
}
}
if (options.hasLoginPrivateKeyOption()) {
if (options.hasLoginPrivateKey()) {
builder.privateKey(options.getLoginPrivateKey());
} else {
builder.noPrivateKey();
}
}
if (options.shouldAuthenticateSudo() != null)
builder.authenticateSudo(true);
return NodeMetadataBuilder.fromNodeMetadata(node).credentials(builder.build()).build();
}
private final class TransformNodesIntoInitializedScriptRunners implements
Function<NodeMetadata, Future<RunScriptOnNode>> {
private final Map<NodeMetadata, Exception> badNodes;
private final Statement script;
private final RunScriptOptions options;
private TransformNodesIntoInitializedScriptRunners(Statement script, RunScriptOptions options,
Map<NodeMetadata, Exception> badNodes) {
this.badNodes = checkNotNull(badNodes, "badNodes");
this.script = checkNotNull(script, "script");
this.options = checkNotNull(options, "options");
}
@Override
public Future<RunScriptOnNode> apply(NodeMetadata node) {
node = updateNodeWithCredentialsIfPresent(node, options);
return executor.submit(initScriptRunnerFactory.create(node, script, options, badNodes));
}
}
}