refactored runScript logic

This commit is contained in:
Adrian Cole 2011-01-23 12:19:28 -08:00
parent c34b973af3
commit 0455e0f509
37 changed files with 1159 additions and 544 deletions

View File

@ -28,6 +28,7 @@ import java.util.Set;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
@ -37,6 +38,7 @@ import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder; import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.NodeState; import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.OperatingSystem; import org.jclouds.compute.domain.OperatingSystem;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope; import org.jclouds.domain.LocationScope;
@ -55,15 +57,16 @@ import com.google.common.collect.Iterables;
*/ */
@Singleton @Singleton
public class ServerToNodeMetadata implements Function<Server, NodeMetadata> { public class ServerToNodeMetadata implements Function<Server, NodeMetadata> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
protected final Supplier<Location> location; protected final Supplier<Location> location;
protected final Map<String, Credentials> credentialStore; protected final Map<String, Credentials> credentialStore;
protected final Map<ServerStatus, NodeState> serverToNodeState; protected final Map<ServerStatus, NodeState> serverToNodeState;
protected final Supplier<Set<? extends Image>> images; protected final Supplier<Set<? extends Image>> images;
protected final Supplier<Set<? extends Hardware>> hardwares; protected final Supplier<Set<? extends Hardware>> hardwares;
@Resource
protected Logger logger = Logger.NULL;
private static class FindImageForServer implements Predicate<Image> { private static class FindImageForServer implements Predicate<Image> {
private final Server instance; private final Server instance;

View File

@ -22,8 +22,8 @@ package org.jclouds.ec2.compute;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.Map.Entry;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import javax.inject.Inject; import javax.inject.Inject;
@ -49,8 +49,8 @@ import org.jclouds.compute.strategy.ListNodesStrategy;
import org.jclouds.compute.strategy.RebootNodeStrategy; import org.jclouds.compute.strategy.RebootNodeStrategy;
import org.jclouds.compute.strategy.ResumeNodeStrategy; import org.jclouds.compute.strategy.ResumeNodeStrategy;
import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy; import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy;
import org.jclouds.compute.strategy.RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import org.jclouds.compute.strategy.SuspendNodeStrategy; import org.jclouds.compute.strategy.SuspendNodeStrategy;
import org.jclouds.compute.util.ComputeUtils;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.ec2.EC2Client; import org.jclouds.ec2.EC2Client;
@ -89,15 +89,16 @@ public class EC2ComputeService extends BaseComputeService {
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider, Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider,
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning, @Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning,
@Named("NODE_TERMINATED") Predicate<NodeMetadata> nodeTerminated, @Named("NODE_TERMINATED") Predicate<NodeMetadata> nodeTerminated,
@Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended, ComputeUtils utils, Timeouts timeouts, @Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended,
RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory statementRunner, Timeouts timeouts,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, EC2Client ec2Client, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, EC2Client ec2Client,
Map<RegionAndName, KeyPair> credentialsMap, @Named("SECURITY") Map<RegionAndName, String> securityGroupMap, Map<RegionAndName, KeyPair> credentialsMap, @Named("SECURITY") Map<RegionAndName, String> securityGroupMap,
@Named("PLACEMENT") Map<RegionAndName, String> placementGroupMap, @Named("PLACEMENT") Map<RegionAndName, String> placementGroupMap,
@Named("DELETED") Predicate<PlacementGroup> placementGroupDeleted) { @Named("DELETED") Predicate<PlacementGroup> placementGroupDeleted) {
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy, super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, stopNodeStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy,
templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, nodeSuspended, utils, stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
timeouts, executor); nodeSuspended, statementRunner, timeouts, executor);
this.ec2Client = ec2Client; this.ec2Client = ec2Client;
this.credentialsMap = credentialsMap; this.credentialsMap = credentialsMap;
this.securityGroupMap = securityGroupMap; this.securityGroupMap = securityGroupMap;
@ -129,8 +130,8 @@ public class EC2ComputeService extends BaseComputeService {
} catch (UnsupportedOperationException e) { } catch (UnsupportedOperationException e) {
} catch (HttpResponseException e) { } catch (HttpResponseException e) {
// Eucalyptus does not support placement groups yet. // Eucalyptus does not support placement groups yet.
if (!(e.getResponse().getStatusCode() == 400 && context.getProviderSpecificContext().getProvider() if (!(e.getResponse().getStatusCode() == 400 && context.getProviderSpecificContext().getProvider().equals(
.equals("eucalyptus"))) "eucalyptus")))
throw e; throw e;
} }
} }

View File

@ -34,6 +34,7 @@ import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.aws.util.AWSUtils; import org.jclouds.aws.util.AWSUtils;
import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
@ -52,6 +53,7 @@ import com.google.common.base.Function;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
/** /**
* creates futures that correlate to * creates futures that correlate to
@ -68,7 +70,7 @@ public class EC2RunNodesAndAddToSetStrategy implements RunNodesAndAddToSetStrate
@VisibleForTesting @VisibleForTesting
final EC2Client client; final EC2Client client;
@VisibleForTesting @VisibleForTesting
final CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions; final CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize;
@VisibleForTesting @VisibleForTesting
final Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata; final Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata;
@VisibleForTesting @VisibleForTesting
@ -80,14 +82,14 @@ public class EC2RunNodesAndAddToSetStrategy implements RunNodesAndAddToSetStrate
@Inject @Inject
EC2RunNodesAndAddToSetStrategy( EC2RunNodesAndAddToSetStrategy(
EC2Client client, EC2Client client,
CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions, CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
@Named("PRESENT") Predicate<RunningInstance> instancePresent, @Named("PRESENT") Predicate<RunningInstance> instancePresent,
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata, Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
Function<RunningInstance, Credentials> instanceToCredentials, Map<String, Credentials> credentialStore, Function<RunningInstance, Credentials> instanceToCredentials, Map<String, Credentials> credentialStore,
ComputeUtils utils) { ComputeUtils utils) {
this.client = client; this.client = client;
this.instancePresent = instancePresent; this.instancePresent = instancePresent;
this.createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions = createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions; this.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = createKeyPairAndSecurityGroupsAsNeededAndReturncustomize;
this.runningInstanceToNodeMetadata = runningInstanceToNodeMetadata; this.runningInstanceToNodeMetadata = runningInstanceToNodeMetadata;
this.instanceToCredentials = instanceToCredentials; this.instanceToCredentials = instanceToCredentials;
this.credentialStore = credentialStore; this.credentialStore = credentialStore;
@ -96,7 +98,7 @@ public class EC2RunNodesAndAddToSetStrategy implements RunNodesAndAddToSetStrate
@Override @Override
public Map<?, Future<Void>> execute(String tag, int count, Template template, Set<NodeMetadata> goodNodes, public Map<?, Future<Void>> execute(String tag, int count, Template template, Set<NodeMetadata> goodNodes,
Map<NodeMetadata, Exception> badNodes) { Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
Reservation<? extends RunningInstance> reservation = createKeyPairAndSecurityGroupsAsNeededThenRunInstances(tag, Reservation<? extends RunningInstance> reservation = createKeyPairAndSecurityGroupsAsNeededThenRunInstances(tag,
count, template); count, template);
@ -111,8 +113,8 @@ public class EC2RunNodesAndAddToSetStrategy implements RunNodesAndAddToSetStrate
populateCredentials(reservation); populateCredentials(reservation);
} }
return utils.runOptionsOnNodesAndAddToGoodSetOrPutExceptionIntoBadMap(template.getOptions(), transform( return utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(template.getOptions(), transform(reservation,
reservation, runningInstanceToNodeMetadata), goodNodes, badNodes); runningInstanceToNodeMetadata), goodNodes, badNodes, customizationResponses);
} }
protected void populateCredentials(Reservation<? extends RunningInstance> reservation) { protected void populateCredentials(Reservation<? extends RunningInstance> reservation) {
@ -129,7 +131,7 @@ public class EC2RunNodesAndAddToSetStrategy implements RunNodesAndAddToSetStrate
String region = AWSUtils.getRegionFromLocationOrNull(template.getLocation()); String region = AWSUtils.getRegionFromLocationOrNull(template.getLocation());
String zone = getZoneFromLocationOrNull(template.getLocation()); String zone = getZoneFromLocationOrNull(template.getLocation());
RunInstancesOptions instanceOptions = createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.execute(region, RunInstancesOptions instanceOptions = createKeyPairAndSecurityGroupsAsNeededAndReturncustomize.execute(region,
tag, template); tag, template);
if (EC2TemplateOptions.class.cast(template.getOptions()).isMonitoringEnabled()) if (EC2TemplateOptions.class.cast(template.getOptions()).isMonitoringEnabled())

View File

@ -29,8 +29,6 @@ import java.util.concurrent.ExecutorService;
import javax.inject.Provider; import javax.inject.Provider;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.services.PlacementGroupClient;
import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
import org.jclouds.compute.strategy.DestroyNodeStrategy; import org.jclouds.compute.strategy.DestroyNodeStrategy;
@ -39,8 +37,10 @@ import org.jclouds.compute.strategy.ListNodesStrategy;
import org.jclouds.compute.strategy.RebootNodeStrategy; import org.jclouds.compute.strategy.RebootNodeStrategy;
import org.jclouds.compute.strategy.ResumeNodeStrategy; import org.jclouds.compute.strategy.ResumeNodeStrategy;
import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy; import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy;
import org.jclouds.compute.strategy.RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import org.jclouds.compute.strategy.SuspendNodeStrategy; import org.jclouds.compute.strategy.SuspendNodeStrategy;
import org.jclouds.compute.util.ComputeUtils; import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.services.PlacementGroupClient;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
@ -62,8 +62,9 @@ public class EC2ComputeServiceTest {
createMock(DestroyNodeStrategy.class), createMock(ResumeNodeStrategy.class), createMock(DestroyNodeStrategy.class), createMock(ResumeNodeStrategy.class),
createMock(SuspendNodeStrategy.class), createMock(Provider.class), createMock(Provider.class), createMock(SuspendNodeStrategy.class), createMock(Provider.class), createMock(Provider.class),
createMock(Predicate.class), createMock(Predicate.class), createMock(Predicate.class), createMock(Predicate.class), createMock(Predicate.class), createMock(Predicate.class),
createMock(ComputeUtils.class), createMock(Timeouts.class), createMock(ExecutorService.class), client, createMock(RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory.class),
createMock(Map.class), createMock(Map.class), createMock(Map.class), createMock(Predicate.class)); createMock(Timeouts.class), createMock(ExecutorService.class), client, createMock(Map.class),
createMock(Map.class), createMock(Map.class), createMock(Predicate.class));
PlacementGroupClient placementClient = createMock(PlacementGroupClient.class); PlacementGroupClient placementClient = createMock(PlacementGroupClient.class);

View File

@ -100,15 +100,15 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
replay(strategy); replay(strategy);
// run // run
RunInstancesOptions runOptions = strategy.execute(region, tag, template); RunInstancesOptions customize = strategy.execute(region, tag, template);
assertEquals(runOptions.buildQueryParameters(), ImmutableMultimap.<String, String> of()); assertEquals(customize.buildQueryParameters(), ImmutableMultimap.<String, String> of());
assertEquals( assertEquals(
runOptions.buildFormParameters().entries(), customize.buildFormParameters().entries(),
ImmutableMultimap.<String, String> of("InstanceType", size.getProviderId(), "SecurityGroup.1", ImmutableMultimap.<String, String> of("InstanceType", size.getProviderId(), "SecurityGroup.1",
generatedGroup, "KeyName", systemGeneratedKeyPairName).entries()); generatedGroup, "KeyName", systemGeneratedKeyPairName).entries());
assertEquals(runOptions.buildMatrixParameters(), ImmutableMultimap.<String, String> of()); assertEquals(customize.buildMatrixParameters(), ImmutableMultimap.<String, String> of());
assertEquals(runOptions.buildRequestHeaders(), ImmutableMultimap.<String, String> of()); assertEquals(customize.buildRequestHeaders(), ImmutableMultimap.<String, String> of());
assertEquals(runOptions.buildStringPayload(), null); assertEquals(customize.buildStringPayload(), null);
// verify mocks // verify mocks
verify(options); verify(options);
@ -159,16 +159,16 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
replay(strategy); replay(strategy);
// run // run
RunInstancesOptions runOptions = strategy.execute(region, tag, template); RunInstancesOptions customize = strategy.execute(region, tag, template);
assertEquals(runOptions.buildQueryParameters(), ImmutableMultimap.<String, String> of()); assertEquals(customize.buildQueryParameters(), ImmutableMultimap.<String, String> of());
assertEquals( assertEquals(
runOptions.buildFormParameters().entries(), customize.buildFormParameters().entries(),
ImmutableMultimap.<String, String> of("InstanceType", size.getProviderId(), "SecurityGroup.1", ImmutableMultimap.<String, String> of("InstanceType", size.getProviderId(), "SecurityGroup.1",
generatedGroup, "KeyName", systemGeneratedKeyPairName, "Placement.GroupName", generatedGroup) generatedGroup, "KeyName", systemGeneratedKeyPairName, "Placement.GroupName", generatedGroup)
.entries()); .entries());
assertEquals(runOptions.buildMatrixParameters(), ImmutableMultimap.<String, String> of()); assertEquals(customize.buildMatrixParameters(), ImmutableMultimap.<String, String> of());
assertEquals(runOptions.buildRequestHeaders(), ImmutableMultimap.<String, String> of()); assertEquals(customize.buildRequestHeaders(), ImmutableMultimap.<String, String> of());
assertEquals(runOptions.buildStringPayload(), null); assertEquals(customize.buildStringPayload(), null);
// verify mocks // verify mocks
verify(options); verify(options);
@ -219,16 +219,16 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
replay(strategy); replay(strategy);
// run // run
RunInstancesOptions runOptions = strategy.execute(region, tag, template); RunInstancesOptions customize = strategy.execute(region, tag, template);
assertEquals(runOptions.buildQueryParameters(), ImmutableMultimap.<String, String> of()); assertEquals(customize.buildQueryParameters(), ImmutableMultimap.<String, String> of());
assertEquals( assertEquals(
runOptions.buildFormParameters().entries(), customize.buildFormParameters().entries(),
ImmutableMultimap.<String, String> of("InstanceType", size.getProviderId(), "SecurityGroup.1", ImmutableMultimap.<String, String> of("InstanceType", size.getProviderId(), "SecurityGroup.1",
generatedGroup, "KeyName", systemGeneratedKeyPairName, "Placement.GroupName", generatedGroup) generatedGroup, "KeyName", systemGeneratedKeyPairName, "Placement.GroupName", generatedGroup)
.entries()); .entries());
assertEquals(runOptions.buildMatrixParameters(), ImmutableMultimap.<String, String> of()); assertEquals(customize.buildMatrixParameters(), ImmutableMultimap.<String, String> of());
assertEquals(runOptions.buildRequestHeaders(), ImmutableMultimap.<String, String> of()); assertEquals(customize.buildRequestHeaders(), ImmutableMultimap.<String, String> of());
assertEquals(runOptions.buildStringPayload(), null); assertEquals(customize.buildStringPayload(), null);
// verify mocks // verify mocks
verify(options); verify(options);
@ -274,15 +274,15 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
replay(strategy); replay(strategy);
// run // run
RunInstancesOptions runOptions = strategy.execute(region, tag, template); RunInstancesOptions customize = strategy.execute(region, tag, template);
assertEquals(runOptions.buildQueryParameters(), ImmutableMultimap.<String, String> of()); assertEquals(customize.buildQueryParameters(), ImmutableMultimap.<String, String> of());
assertEquals( assertEquals(
runOptions.buildFormParameters().entries(), customize.buildFormParameters().entries(),
ImmutableMultimap.<String, String> of("InstanceType", size.getProviderId(), "SubnetId", "1", "KeyName", ImmutableMultimap.<String, String> of("InstanceType", size.getProviderId(), "SubnetId", "1", "KeyName",
systemGeneratedKeyPairName).entries()); systemGeneratedKeyPairName).entries());
assertEquals(runOptions.buildMatrixParameters(), ImmutableMultimap.<String, String> of()); assertEquals(customize.buildMatrixParameters(), ImmutableMultimap.<String, String> of());
assertEquals(runOptions.buildRequestHeaders(), ImmutableMultimap.<String, String> of()); assertEquals(customize.buildRequestHeaders(), ImmutableMultimap.<String, String> of());
assertEquals(runOptions.buildStringPayload(), null); assertEquals(customize.buildStringPayload(), null);
// verify mocks // verify mocks
verify(options); verify(options);
@ -331,15 +331,15 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
replay(strategy); replay(strategy);
// run // run
RunInstancesOptions runOptions = strategy.execute(region, tag, template); RunInstancesOptions customize = strategy.execute(region, tag, template);
assertEquals(runOptions.buildQueryParameters(), ImmutableMultimap.<String, String> of()); assertEquals(customize.buildQueryParameters(), ImmutableMultimap.<String, String> of());
assertEquals( assertEquals(
runOptions.buildFormParameters().entries(), customize.buildFormParameters().entries(),
ImmutableMultimap.<String, String> of("InstanceType", size.getProviderId(), "SecurityGroup.1", "group", ImmutableMultimap.<String, String> of("InstanceType", size.getProviderId(), "SecurityGroup.1", "group",
"KeyName", systemGeneratedKeyPairName, "UserData", Base64.encodeBytes("hello".getBytes())).entries()); "KeyName", systemGeneratedKeyPairName, "UserData", Base64.encodeBytes("hello".getBytes())).entries());
assertEquals(runOptions.buildMatrixParameters(), ImmutableMultimap.<String, String> of()); assertEquals(customize.buildMatrixParameters(), ImmutableMultimap.<String, String> of());
assertEquals(runOptions.buildRequestHeaders(), ImmutableMultimap.<String, String> of()); assertEquals(customize.buildRequestHeaders(), ImmutableMultimap.<String, String> of());
assertEquals(runOptions.buildStringPayload(), null); assertEquals(customize.buildStringPayload(), null);
// verify mocks // verify mocks
verify(options); verify(options);

View File

@ -31,6 +31,7 @@ import java.util.Set;
import org.easymock.IArgumentMatcher; import org.easymock.IArgumentMatcher;
import org.jclouds.aws.domain.Region; import org.jclouds.aws.domain.Region;
import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
@ -54,6 +55,7 @@ import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
/** /**
* @author Adrian Cole * @author Adrian Cole
@ -102,15 +104,14 @@ public class EC2RunNodesAndAddToSetStrategyTest {
InstanceClient instanceClient = createMock(InstanceClient.class); InstanceClient instanceClient = createMock(InstanceClient.class);
RunInstancesOptions ec2Options = createMock(RunInstancesOptions.class); RunInstancesOptions ec2Options = createMock(RunInstancesOptions.class);
RunningInstance instance = createMock(RunningInstance.class); RunningInstance instance = createMock(RunningInstance.class);
Reservation<? extends RunningInstance> reservation = new Reservation<RunningInstance>(region, Reservation<? extends RunningInstance> reservation = new Reservation<RunningInstance>(region, ImmutableSet
ImmutableSet.<String> of(), ImmutableSet.<RunningInstance> of(instance), "ownerId", "requesterId", .<String> of(), ImmutableSet.<RunningInstance> of(instance), "ownerId", "requesterId", "reservationId");
"reservationId");
NodeMetadata nodeMetadata = createMock(NodeMetadata.class); NodeMetadata nodeMetadata = createMock(NodeMetadata.class);
// setup expectations // setup expectations
expect(strategy.client.getInstanceServices()).andReturn(instanceClient).atLeastOnce(); expect(strategy.client.getInstanceServices()).andReturn(instanceClient).atLeastOnce();
expect( expect(
strategy.createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.execute(region, input.tag, strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize.execute(region, input.tag,
input.template)).andReturn(ec2Options); input.template)).andReturn(ec2Options);
expect(input.template.getLocation()).andReturn(input.location).atLeastOnce(); expect(input.template.getLocation()).andReturn(input.location).atLeastOnce();
expect(input.template.getImage()).andReturn(input.image).atLeastOnce(); expect(input.template.getImage()).andReturn(input.image).atLeastOnce();
@ -130,8 +131,9 @@ public class EC2RunNodesAndAddToSetStrategyTest {
expect(strategy.runningInstanceToNodeMetadata.apply(instance)).andReturn(nodeMetadata); expect(strategy.runningInstanceToNodeMetadata.apply(instance)).andReturn(nodeMetadata);
expect( expect(
strategy.utils.runOptionsOnNodesAndAddToGoodSetOrPutExceptionIntoBadMap(eq(input.options), strategy.utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(eq(input.options),
containsNodeMetadata(nodeMetadata), eq(input.nodes), eq(input.badNodes))).andReturn(null); containsNodeMetadata(nodeMetadata), eq(input.nodes), eq(input.badNodes),
eq(input.customization))).andReturn(null);
// replay mocks // replay mocks
replay(instanceClient); replay(instanceClient);
@ -142,7 +144,7 @@ public class EC2RunNodesAndAddToSetStrategyTest {
replayStrategy(strategy); replayStrategy(strategy);
// run // run
strategy.execute(input.tag, input.count, input.template, input.nodes, input.badNodes); strategy.execute(input.tag, input.count, input.template, input.nodes, input.badNodes, input.customization);
// verify mocks // verify mocks
verify(instanceClient); verify(instanceClient);
@ -166,6 +168,7 @@ public class EC2RunNodesAndAddToSetStrategyTest {
Template template = createMock(Template.class); Template template = createMock(Template.class);
Set<NodeMetadata> nodes = createMock(Set.class); Set<NodeMetadata> nodes = createMock(Set.class);
Map<NodeMetadata, Exception> badNodes = createMock(Map.class); Map<NodeMetadata, Exception> badNodes = createMock(Map.class);
Multimap<NodeMetadata, CustomizationResponse> customization = createMock(Multimap.class);
Hardware hardware = createMock(Hardware.class); Hardware hardware = createMock(Hardware.class);
Image image = createMock(Image.class); Image image = createMock(Image.class);
final Location location; final Location location;
@ -181,6 +184,7 @@ public class EC2RunNodesAndAddToSetStrategyTest {
replay(image); replay(image);
replay(nodes); replay(nodes);
replay(badNodes); replay(badNodes);
replay(customization);
replay(options); replay(options);
} }
@ -190,12 +194,13 @@ public class EC2RunNodesAndAddToSetStrategyTest {
verify(image); verify(image);
verify(nodes); verify(nodes);
verify(badNodes); verify(badNodes);
verify(customization);
verify(options); verify(options);
} }
} }
private void verifyStrategy(EC2RunNodesAndAddToSetStrategy strategy) { private void verifyStrategy(EC2RunNodesAndAddToSetStrategy strategy) {
verify(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions); verify(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize);
verify(strategy.client); verify(strategy.client);
verify(strategy.instancePresent); verify(strategy.instancePresent);
verify(strategy.runningInstanceToNodeMetadata); verify(strategy.runningInstanceToNodeMetadata);
@ -207,18 +212,18 @@ public class EC2RunNodesAndAddToSetStrategyTest {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private EC2RunNodesAndAddToSetStrategy setupStrategy() { private EC2RunNodesAndAddToSetStrategy setupStrategy() {
EC2Client client = createMock(EC2Client.class); EC2Client client = createMock(EC2Client.class);
CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions = createMock(CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions.class); CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = createMock(CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions.class);
Predicate<RunningInstance> instanceStateRunning = createMock(Predicate.class); Predicate<RunningInstance> instanceStateRunning = createMock(Predicate.class);
RunningInstanceToNodeMetadata runningInstanceToNodeMetadata = createMock(RunningInstanceToNodeMetadata.class); RunningInstanceToNodeMetadata runningInstanceToNodeMetadata = createMock(RunningInstanceToNodeMetadata.class);
Function<RunningInstance, Credentials> instanceToCredentials = createMock(Function.class); Function<RunningInstance, Credentials> instanceToCredentials = createMock(Function.class);
Map<String, Credentials> credentialStore = createMock(Map.class); Map<String, Credentials> credentialStore = createMock(Map.class);
ComputeUtils utils = createMock(ComputeUtils.class); ComputeUtils utils = createMock(ComputeUtils.class);
return new EC2RunNodesAndAddToSetStrategy(client, createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions, return new EC2RunNodesAndAddToSetStrategy(client, createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
instanceStateRunning, runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils); instanceStateRunning, runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils);
} }
private void replayStrategy(EC2RunNodesAndAddToSetStrategy strategy) { private void replayStrategy(EC2RunNodesAndAddToSetStrategy strategy) {
replay(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions); replay(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize);
replay(strategy.client); replay(strategy.client);
replay(strategy.instancePresent); replay(strategy.instancePresent);
replay(strategy.runningInstanceToNodeMetadata); replay(strategy.runningInstanceToNodeMetadata);

View File

@ -45,8 +45,8 @@ import org.jclouds.compute.strategy.ListNodesStrategy;
import org.jclouds.compute.strategy.RebootNodeStrategy; import org.jclouds.compute.strategy.RebootNodeStrategy;
import org.jclouds.compute.strategy.ResumeNodeStrategy; import org.jclouds.compute.strategy.ResumeNodeStrategy;
import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy; import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy;
import org.jclouds.compute.strategy.RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import org.jclouds.compute.strategy.SuspendNodeStrategy; import org.jclouds.compute.strategy.SuspendNodeStrategy;
import org.jclouds.compute.util.ComputeUtils;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.vcloud.terremark.compute.domain.KeyPairCredentials; import org.jclouds.vcloud.terremark.compute.domain.KeyPairCredentials;
@ -75,13 +75,14 @@ public class TerremarkVCloudComputeService extends BaseComputeService {
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider, Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider,
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning, @Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning,
@Named("NODE_TERMINATED") Predicate<NodeMetadata> nodeTerminated, @Named("NODE_TERMINATED") Predicate<NodeMetadata> nodeTerminated,
@Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended, ComputeUtils utils, Timeouts timeouts, @Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended,
RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory statementRunner, Timeouts timeouts,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, CleanupOrphanKeys cleanupOrphanKeys, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, CleanupOrphanKeys cleanupOrphanKeys,
ConcurrentMap<OrgAndName, KeyPairCredentials> credentialsMap, NodeMetadataToOrgAndName nodeToOrgAndName) { ConcurrentMap<OrgAndName, KeyPairCredentials> credentialsMap, NodeMetadataToOrgAndName nodeToOrgAndName) {
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy, super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, resumeNodeStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, resumeNodeStrategy,
suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
nodeSuspended, utils, timeouts, executor); nodeSuspended, statementRunner, timeouts, executor);
this.cleanupOrphanKeys = cleanupOrphanKeys; this.cleanupOrphanKeys = cleanupOrphanKeys;
} }

View File

@ -115,14 +115,6 @@ public class TerremarkVCloudComputeServiceContextModule extends VCloudExpressCom
return new ConcurrentHashMap<OrgAndName, KeyPairCredentials>(); return new ConcurrentHashMap<OrgAndName, KeyPairCredentials>();
} }
// TODO
// @Override
// protected void bindLoadBalancer() {
// bind(LoadBalanceNodesStrategy.class).to(TerremarkLoadBalanceNodesStrategy.class);
// bind(DestroyLoadBalancerStrategy.class).to(TerremarkDestroyLoadBalancerStrategy.class);
// }
//
@Named("PASSWORD") @Named("PASSWORD")
@Provides @Provides
String providePassword(SecureRandom random) { String providePassword(SecureRandom random) {

View File

@ -30,15 +30,18 @@ import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.strategy.AddNodeWithTagStrategy; import org.jclouds.compute.strategy.AddNodeWithTagStrategy;
import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import org.jclouds.compute.strategy.ListNodesStrategy; import org.jclouds.compute.strategy.ListNodesStrategy;
import org.jclouds.compute.strategy.impl.EncodeTagIntoNameRunNodesAndAddToSetStrategy; import org.jclouds.compute.strategy.impl.EncodeTagIntoNameRunNodesAndAddToSetStrategy;
import org.jclouds.compute.util.ComputeUtils;
import org.jclouds.domain.LocationScope; import org.jclouds.domain.LocationScope;
import org.jclouds.vcloud.terremark.compute.options.TerremarkVCloudTemplateOptions; import org.jclouds.vcloud.terremark.compute.options.TerremarkVCloudTemplateOptions;
import com.google.common.collect.Multimap;
/** /**
* creates futures that correlate to * creates futures that correlate to
* *
@ -50,23 +53,27 @@ public class TerremarkEncodeTagIntoNameRunNodesAndAddToSetStrategy extends Encod
private final CreateNewKeyPairUnlessUserSpecifiedOtherwise createNewKeyPairUnlessUserSpecifiedOtherwise; private final CreateNewKeyPairUnlessUserSpecifiedOtherwise createNewKeyPairUnlessUserSpecifiedOtherwise;
@Inject @Inject
protected TerremarkEncodeTagIntoNameRunNodesAndAddToSetStrategy(AddNodeWithTagStrategy addNodeWithTagStrategy, protected TerremarkEncodeTagIntoNameRunNodesAndAddToSetStrategy(
ListNodesStrategy listNodesStrategy, @Named("NAMING_CONVENTION") String nodeNamingConvention, AddNodeWithTagStrategy addNodeWithTagStrategy,
ComputeUtils utils, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, ListNodesStrategy listNodesStrategy,
@Named("NAMING_CONVENTION") String nodeNamingConvention,
CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor,
CreateNewKeyPairUnlessUserSpecifiedOtherwise createNewKeyPairUnlessUserSpecifiedOtherwise) { CreateNewKeyPairUnlessUserSpecifiedOtherwise createNewKeyPairUnlessUserSpecifiedOtherwise) {
super(addNodeWithTagStrategy, listNodesStrategy, nodeNamingConvention, utils, executor); super(addNodeWithTagStrategy, listNodesStrategy, nodeNamingConvention, executor,
customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory);
this.createNewKeyPairUnlessUserSpecifiedOtherwise = createNewKeyPairUnlessUserSpecifiedOtherwise; this.createNewKeyPairUnlessUserSpecifiedOtherwise = createNewKeyPairUnlessUserSpecifiedOtherwise;
} }
@Override @Override
public Map<?, Future<Void>> execute(String tag, int count, Template template, Set<NodeMetadata> nodes, public Map<?, Future<Void>> execute(String tag, int count, Template template, Set<NodeMetadata> goodNodes,
Map<NodeMetadata, Exception> badNodes) { Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
assert template.getLocation().getParent().getScope() == LocationScope.REGION : "template location should have a parent of org, which should be mapped to region: " assert template.getLocation().getParent().getScope() == LocationScope.REGION : "template location should have a parent of org, which should be mapped to region: "
+ template.getLocation(); + template.getLocation();
String orgId = template.getLocation().getParent().getId(); String orgId = template.getLocation().getParent().getId();
assert orgId.startsWith("http") : "parent id should be a rest url: " + template.getLocation().getParent(); assert orgId.startsWith("http") : "parent id should be a rest url: " + template.getLocation().getParent();
createNewKeyPairUnlessUserSpecifiedOtherwise.execute(URI.create(orgId), tag, template.getImage() createNewKeyPairUnlessUserSpecifiedOtherwise.execute(URI.create(orgId), tag, template.getImage()
.getDefaultCredentials().identity, template.getOptions().as(TerremarkVCloudTemplateOptions.class)); .getDefaultCredentials().identity, template.getOptions().as(TerremarkVCloudTemplateOptions.class));
return super.execute(tag, count, template, nodes, badNodes); return super.execute(tag, count, template, goodNodes, badNodes, customizationResponses);
} }
} }

View File

@ -23,9 +23,9 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.internal.BaseComputeService; import org.jclouds.compute.internal.BaseComputeService;
@ -33,6 +33,7 @@ import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.io.Payload; import org.jclouds.io.Payload;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.ssh.ExecResponse; import org.jclouds.ssh.ExecResponse;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
@ -238,11 +239,12 @@ public interface ComputeService {
* org.jclouds.compute.options.RunScriptOptions) * org.jclouds.compute.options.RunScriptOptions)
* @see org.jclouds.compute.predicates.NodePredicates#runningWithTag(String) * @see org.jclouds.compute.predicates.NodePredicates#runningWithTag(String)
*/ */
@Deprecated
Map<? extends NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter, Payload runScript) Map<? extends NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter, Payload runScript)
throws RunScriptOnNodesException; throws RunScriptOnNodesException;
/** /**
* Run the script on all nodes with the specific tag. * Run the script on all nodes with the specific predicate.
* *
* @param filter * @param filter
* Predicate-based filter to define on which nodes the script is to be executed * Predicate-based filter to define on which nodes the script is to be executed
@ -257,7 +259,46 @@ public interface ComputeService {
* @see org.jclouds.compute.predicates.NodePredicates#runningWithTag(String) * @see org.jclouds.compute.predicates.NodePredicates#runningWithTag(String)
* @see org.jclouds.io.Payloads * @see org.jclouds.io.Payloads
*/ */
@Deprecated
Map<? extends NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter, Map<? extends NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter,
Payload runScript, RunScriptOptions options) throws RunScriptOnNodesException; Payload runScript, RunScriptOptions options) throws RunScriptOnNodesException;
/**
* Run the script on all nodes with the specific predicate.
*
* @param filter
* Predicate-based filter to define on which nodes the script is to be executed
* @param runScript
* string containing the script to run
* @param options
* nullable options to how to run the script, whether to override credentials
* @return map with node identifiers and corresponding responses
* @throws RunScriptOnNodesException
* if anything goes wrong during script execution
*
* @see org.jclouds.compute.predicates.NodePredicates#runningWithTag(String)
* @see org.jclouds.scriptbuilder.domain.Statements
*/
Map<? extends NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter, String runScript,
RunScriptOptions options) throws RunScriptOnNodesException;
/**
* Run the script on all nodes with the specific predicate.
*
* @param filter
* Predicate-based filter to define on which nodes the script is to be executed
* @param runScript
* statement containing the script to run
* @param options
* nullable options to how to run the script, whether to override credentials
* @return map with node identifiers and corresponding responses
* @throws RunScriptOnNodesException
* if anything goes wrong during script execution
*
* @see org.jclouds.compute.predicates.NodePredicates#runningWithTag(String)
* @see org.jclouds.scriptbuilder.domain.Statements
*/
Map<? extends NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter,
Statement runScript, RunScriptOptions options) throws RunScriptOnNodesException;
} }

View File

@ -28,7 +28,7 @@ import javax.annotation.Nullable;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.options.RunScriptOptions; import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.io.Payload; import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.ssh.ExecResponse; import org.jclouds.ssh.ExecResponse;
/** /**
@ -39,13 +39,13 @@ public class RunScriptOnNodesException extends Exception {
/** The serialVersionUID */ /** The serialVersionUID */
private static final long serialVersionUID = -2272965726680821281L; private static final long serialVersionUID = -2272965726680821281L;
private final Payload runScript; private final Statement runScript;
private final RunScriptOptions options; private final RunScriptOptions options;
private final Map<NodeMetadata, ExecResponse> successfulNodes; private final Map<NodeMetadata, ExecResponse> successfulNodes;
private final Map<? extends NodeMetadata, ? extends Throwable> failedNodes; private final Map<? extends NodeMetadata, ? extends Throwable> failedNodes;
private final Map<?, Exception> executionExceptions; private final Map<?, Exception> executionExceptions;
public RunScriptOnNodesException(final Payload runScript, @Nullable final RunScriptOptions options, public RunScriptOnNodesException(Statement runScript, @Nullable RunScriptOptions options,
Map<NodeMetadata, ExecResponse> successfulNodes, Map<?, Exception> executionExceptions, Map<NodeMetadata, ExecResponse> successfulNodes, Map<?, Exception> executionExceptions,
Map<? extends NodeMetadata, ? extends Throwable> failedNodes) { Map<? extends NodeMetadata, ? extends Throwable> failedNodes) {
super(String.format("error runScript on filtered nodes options(%s)%n%s%n%s", options, super(String.format("error runScript on filtered nodes options(%s)%n%s%n%s", options,
@ -66,8 +66,7 @@ public class RunScriptOnNodesException extends Exception {
/** /**
* *
* @return Nodes that performed startup without error, but incurred problems * @return Nodes that performed startup without error, but incurred problems applying options
* applying options
*/ */
public Map<?, ? extends Throwable> getExecutionErrors() { public Map<?, ? extends Throwable> getExecutionErrors() {
return executionExceptions; return executionExceptions;
@ -75,14 +74,13 @@ public class RunScriptOnNodesException extends Exception {
/** /**
* *
* @return Nodes that performed startup without error, but incurred problems * @return Nodes that performed startup without error, but incurred problems applying options
* applying options
*/ */
public Map<? extends NodeMetadata, ? extends Throwable> getNodeErrors() { public Map<? extends NodeMetadata, ? extends Throwable> getNodeErrors() {
return failedNodes; return failedNodes;
} }
public Payload getRunScript() { public Statement getRunScript() {
return runScript; return runScript;
} }

View File

@ -22,9 +22,15 @@ package org.jclouds.compute.callables;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Collections; import java.util.Collections;
import java.util.concurrent.Callable;
import javax.annotation.Nullable;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.util.ComputeServiceUtils.SshCallable; 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.OsFamily; import org.jclouds.scriptbuilder.domain.OsFamily;
@ -33,23 +39,51 @@ import org.jclouds.ssh.ExecResponse;
import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshClient;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.inject.assistedinject.Assisted;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public class InitAndStartScriptOnNode implements SshCallable<ExecResponse> { public class StartInitScriptOnNode implements Callable<ExecResponse> {
protected SshClient ssh; @Resource
protected final NodeMetadata node; @Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected final InitBuilder init;
protected final boolean runAsRoot;
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
public InitAndStartScriptOnNode(NodeMetadata node, String name, Statement script, boolean runAsRoot) { public interface Factory {
@Named("blocking")
StartInitScriptOnNode blockOnComplete(NodeMetadata node, @Nullable String name, Statement script,
boolean runAsRoot);
@Named("nonblocking")
StartInitScriptOnNode dontBlockOnComplete(NodeMetadata node, @Nullable String name, Statement script,
boolean runAsRoot);
}
protected final Function<NodeMetadata, SshClient> sshFactory;
protected final NodeMetadata node;
protected final Statement init;
protected final String name;
protected final boolean runAsRoot;
protected SshClient ssh;
@Inject
public StartInitScriptOnNode(Function<NodeMetadata, SshClient> sshFactory, @Assisted NodeMetadata node,
@Assisted @Nullable String name, @Assisted Statement script, @Assisted boolean runAsRoot) {
this.sshFactory = checkNotNull(sshFactory, "sshFactory");
this.node = checkNotNull(node, "node"); this.node = checkNotNull(node, "node");
if (name == null) {
if (checkNotNull(script, "script") instanceof InitBuilder)
name = InitBuilder.class.cast(script).getInstanceName();
else
name = "jclouds-script-" + System.currentTimeMillis();
}
this.init = checkNotNull(script, "script") instanceof InitBuilder ? InitBuilder.class.cast(script) this.init = checkNotNull(script, "script") instanceof InitBuilder ? InitBuilder.class.cast(script)
: createInitScript(checkNotNull(name, "name"), script); : createInitScript(checkNotNull(name, "name"), script);
this.name = checkNotNull(name, "name");
this.runAsRoot = runAsRoot; this.runAsRoot = runAsRoot;
} }
@ -60,13 +94,28 @@ public class InitAndStartScriptOnNode implements SshCallable<ExecResponse> {
@Override @Override
public ExecResponse call() { public ExecResponse call() {
ssh.put(init.getInstanceName(), init.render(OsFamily.UNIX)); ssh = sshFactory.apply(node);
ssh.exec("chmod 755 " + init.getInstanceName()); try {
ssh.connect();
return doCall();
} finally {
if (ssh != null)
ssh.disconnect();
}
}
/**
* ssh client is initialized through this call.
*/
protected ExecResponse doCall() {
ssh.put(name, init.render(OsFamily.UNIX));
ssh.exec("chmod 755 " + name);
runAction("init"); runAction("init");
return runAction("start"); return runAction("start");
} }
private 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);
returnVal = runCommand(command); returnVal = runCommand(command);
@ -84,30 +133,23 @@ public class InitAndStartScriptOnNode implements SshCallable<ExecResponse> {
return returnVal; return returnVal;
} }
@Override
public void setConnection(SshClient ssh, Logger logger) {
this.logger = checkNotNull(logger, "logger");
this.ssh = checkNotNull(ssh, "ssh");
}
@VisibleForTesting @VisibleForTesting
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 = "./" + init.getInstanceName() + " " + action; command = "./" + name + " " + action;
} else if (node.getAdminPassword() != null) { } else if (node.getAdminPassword() != null) {
command = String.format("echo '%s'|sudo -S ./%s %s", node.getAdminPassword(), init.getInstanceName(), action); command = String.format("echo '%s'|sudo -S ./%s %s", node.getAdminPassword(), name, action);
} else { } else {
command = "sudo ./" + init.getInstanceName() + " " + action; command = "sudo ./" + name + " " + action;
} }
return command; return command;
} }
protected String execScriptAsDefaultUser(String action) { protected String execScriptAsDefaultUser(String action) {
return "./" + init.getInstanceName() + " " + action; return "./" + name + " " + action;
} }
@Override
public NodeMetadata getNode() { public NodeMetadata getNode() {
return node; return node;
} }

View File

@ -19,40 +19,48 @@
package org.jclouds.compute.callables; package org.jclouds.compute.callables;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.predicates.ScriptStatusReturnsZero.CommandUsingClient; import org.jclouds.compute.predicates.ScriptStatusReturnsZero.CommandUsingClient;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.ssh.ExecResponse; import org.jclouds.ssh.ExecResponse;
import org.jclouds.ssh.SshClient;
import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.inject.assistedinject.Assisted;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public class RunScriptOnNode extends InitAndStartScriptOnNode { public class StartInitScriptOnNodeAndBlockUntilComplete extends StartInitScriptOnNode {
protected final Predicate<CommandUsingClient> runScriptNotRunning; protected final Predicate<CommandUsingClient> runScriptNotRunning;
public RunScriptOnNode(@Named("SCRIPT_COMPLETE") Predicate<CommandUsingClient> runScriptNotRunning, @Inject
NodeMetadata node, String scriptName, Statement script, boolean runAsRoot) { public StartInitScriptOnNodeAndBlockUntilComplete(
super(node, scriptName, script, runAsRoot); @Named("SCRIPT_COMPLETE") Predicate<CommandUsingClient> runScriptNotRunning,
this.runScriptNotRunning = runScriptNotRunning; Function<NodeMetadata, SshClient> sshFactory, @Assisted NodeMetadata node, @Assisted String scriptName,
@Assisted Statement script, @Assisted boolean runAsRoot) {
super(sshFactory, node, scriptName, script, runAsRoot);
this.runScriptNotRunning = checkNotNull(runScriptNotRunning, "runScriptNotRunning");
} }
@Override @Override
public ExecResponse call() { public ExecResponse doCall() {
ExecResponse returnVal = super.call(); ExecResponse returnVal = super.doCall();
boolean complete = runScriptNotRunning.apply(new CommandUsingClient("./" + init.getInstanceName() + " status", ssh)); boolean complete = runScriptNotRunning.apply(new CommandUsingClient("./" + name + " 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", init.getInstanceName(), node.getCredentials().identity, Iterables.get(node logger.debug("<< stdout from %s as %s@%s\n%s", name, node.getCredentials().identity, Iterables.get(node
.getPublicAddresses(), 0), ssh.exec("./" + init.getInstanceName() + " tail").getOutput()); .getPublicAddresses(), 0), ssh.exec("./" + name + " tail").getOutput());
logger.debug("<< stderr from %s as %s@%s\n%s", init.getInstanceName(), node.getCredentials().identity, Iterables.get(node logger.debug("<< stderr from %s as %s@%s\n%s", name, node.getCredentials().identity, Iterables.get(node
.getPublicAddresses(), 0), ssh.exec("./" + init.getInstanceName() + " tailerr").getOutput()); .getPublicAddresses(), 0), ssh.exec("./" + name + " tailerr").getOutput());
} }
return returnVal; return returnVal;
} }

View File

@ -24,12 +24,15 @@ import static org.jclouds.compute.domain.OsFamily.UBUNTU;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
import org.jclouds.compute.callables.StartInitScriptOnNode;
import org.jclouds.compute.callables.StartInitScriptOnNodeAndBlockUntilComplete;
import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
@ -37,11 +40,17 @@ import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.functions.CreateSshClientOncePortIsListeningOnNode; import org.jclouds.compute.functions.CreateSshClientOncePortIsListeningOnNode;
import org.jclouds.compute.functions.TemplateOptionsToStatement;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import org.jclouds.compute.strategy.RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import org.jclouds.compute.util.ComputeServiceUtils;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.json.Json; import org.jclouds.json.Json;
import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.suppliers.RetryOnTimeOutButNotOnAuthorizationExceptionSupplier; import org.jclouds.rest.suppliers.RetryOnTimeOutButNotOnAuthorizationExceptionSupplier;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshClient;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -52,6 +61,8 @@ import com.google.inject.AbstractModule;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.google.inject.Provides; import com.google.inject.Provides;
import com.google.inject.TypeLiteral; import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import com.google.inject.name.Names;
/** /**
* *
@ -63,6 +74,23 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule {
install(new ComputeServiceTimeoutsModule()); install(new ComputeServiceTimeoutsModule());
bind(new TypeLiteral<Function<NodeMetadata, SshClient>>() { bind(new TypeLiteral<Function<NodeMetadata, SshClient>>() {
}).to(CreateSshClientOncePortIsListeningOnNode.class); }).to(CreateSshClientOncePortIsListeningOnNode.class);
bind(new TypeLiteral<Function<TemplateOptions, Statement>>() {
}).to(TemplateOptionsToStatement.class);
install(new FactoryModuleBuilder().implement(StartInitScriptOnNode.class, Names.named("blocking"),
StartInitScriptOnNodeAndBlockUntilComplete.class).implement(StartInitScriptOnNode.class,
Names.named("nonblocking"), StartInitScriptOnNode.class).build(StartInitScriptOnNode.Factory.class));
install(new FactoryModuleBuilder().implement(new TypeLiteral<Callable<Void>>() {
}, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.class).implement(
new TypeLiteral<Function<NodeMetadata, Void>>() {
}, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.class).build(
CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory.class));
install(new FactoryModuleBuilder().implement(new TypeLiteral<Callable<Void>>() {
}, RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.class).build(
RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory.class));
requestStaticInjection(ComputeServiceUtils.class);
} }
@Provides @Provides

View File

@ -0,0 +1,30 @@
/**
*
* Copyright (C) 2010 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.compute.config;
/**
*
* Designates information related to customization of a resource.
*
* @author Adrian Cole
*/
public interface CustomizationResponse {
}

View File

@ -53,7 +53,6 @@ public class JCloudsNativeComputeServiceAdapterContextModule<S, A> extends
protected void configure() { protected void configure() {
bind(new TypeLiteral<ComputeServiceAdapter<NodeMetadata, Hardware, Image, Location>>() { bind(new TypeLiteral<ComputeServiceAdapter<NodeMetadata, Hardware, Image, Location>>() {
}).to(adapter); }).to(adapter);
bind(IdentityFunction.class).toInstance(IdentityFunction.INSTANCE);
bind(new TypeLiteral<Function<NodeMetadata, NodeMetadata>>() { bind(new TypeLiteral<Function<NodeMetadata, NodeMetadata>>() {
}).to((Class) IdentityFunction.class); }).to((Class) IdentityFunction.class);
bind(new TypeLiteral<Function<Image, Image>>() { bind(new TypeLiteral<Function<Image, Image>>() {

View File

@ -0,0 +1,61 @@
/**
*
* Copyright (C) 2010 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.compute.functions;
import static com.google.common.collect.Lists.newArrayList;
import java.util.List;
import javax.inject.Singleton;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.scriptbuilder.InitBuilder;
import org.jclouds.scriptbuilder.domain.AuthorizeRSAPublicKey;
import org.jclouds.scriptbuilder.domain.InstallRSAPrivateKey;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.StatementList;
import com.google.common.base.Function;
/**
*
* @author Adrian Cole
*/
@Singleton
public class TemplateOptionsToStatement implements Function<TemplateOptions, Statement> {
@Override
public Statement apply(TemplateOptions options) {
List<Statement> bootstrap = newArrayList();
if (options.getPublicKey() != null)
bootstrap.add(new AuthorizeRSAPublicKey(options.getPublicKey()));
if (options.getRunScript() != null)
bootstrap.add(options.getRunScript());
if (options.getPrivateKey() != null)
bootstrap.add(new InstallRSAPrivateKey(options.getPrivateKey()));
if (bootstrap.size() >= 1) {
if (options.getTaskName() == null && !(options.getRunScript() instanceof InitBuilder))
options.nameTask("bootstrap");
return bootstrap.size() == 1 ? bootstrap.get(0) : new StatementList(bootstrap);
}
return null;
}
}

View File

@ -27,10 +27,8 @@ import static com.google.common.base.Predicates.notNull;
import static com.google.common.collect.Iterables.concat; import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Maps.newHashMap;
import static com.google.common.collect.Maps.newLinkedHashMap; import static com.google.common.collect.Maps.newLinkedHashMap;
import static com.google.common.collect.Sets.filter; import static com.google.common.collect.Sets.filter;
import static com.google.common.collect.Sets.newHashSet;
import static com.google.common.collect.Sets.newLinkedHashSet; import static com.google.common.collect.Sets.newLinkedHashSet;
import static com.google.common.util.concurrent.Futures.immediateFuture; import static com.google.common.util.concurrent.Futures.immediateFuture;
import static org.jclouds.compute.predicates.NodePredicates.TERMINATED; import static org.jclouds.compute.predicates.NodePredicates.TERMINATED;
@ -38,6 +36,7 @@ import static org.jclouds.compute.predicates.NodePredicates.all;
import static org.jclouds.concurrent.FutureIterables.awaitCompletion; import static org.jclouds.concurrent.FutureIterables.awaitCompletion;
import static org.jclouds.concurrent.FutureIterables.transformParallel; import static org.jclouds.concurrent.FutureIterables.transformParallel;
import java.io.IOException;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
@ -59,6 +58,7 @@ import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.RunNodesException; import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.RunScriptOnNodesException; import org.jclouds.compute.RunScriptOnNodesException;
import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
@ -76,13 +76,14 @@ import org.jclouds.compute.strategy.ListNodesStrategy;
import org.jclouds.compute.strategy.RebootNodeStrategy; import org.jclouds.compute.strategy.RebootNodeStrategy;
import org.jclouds.compute.strategy.ResumeNodeStrategy; import org.jclouds.compute.strategy.ResumeNodeStrategy;
import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy; import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy;
import org.jclouds.compute.strategy.RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import org.jclouds.compute.strategy.SuspendNodeStrategy; import org.jclouds.compute.strategy.SuspendNodeStrategy;
import org.jclouds.compute.util.ComputeUtils;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.io.Payload; import org.jclouds.io.Payload;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.predicates.RetryablePredicate; import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.Statements; import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.ssh.ExecResponse; import org.jclouds.ssh.ExecResponse;
import org.jclouds.util.Strings2; import org.jclouds.util.Strings2;
@ -90,6 +91,9 @@ import org.jclouds.util.Strings2;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.base.Throwables;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
/** /**
* *
@ -104,24 +108,25 @@ public class BaseComputeService implements ComputeService {
protected final ComputeServiceContext context; protected final ComputeServiceContext context;
protected final Map<String, Credentials> credentialStore; protected final Map<String, Credentials> credentialStore;
protected final Supplier<Set<? extends Image>> images;
protected final Supplier<Set<? extends Hardware>> hardwareProfiles; private final Supplier<Set<? extends Image>> images;
protected final Supplier<Set<? extends Location>> locations; private final Supplier<Set<? extends Hardware>> hardwareProfiles;
protected final ListNodesStrategy listNodesStrategy; private final Supplier<Set<? extends Location>> locations;
protected final GetNodeMetadataStrategy getNodeMetadataStrategy; private final ListNodesStrategy listNodesStrategy;
protected final RunNodesAndAddToSetStrategy runNodesAndAddToSetStrategy; private final GetNodeMetadataStrategy getNodeMetadataStrategy;
protected final RebootNodeStrategy rebootNodeStrategy; private final RunNodesAndAddToSetStrategy runNodesAndAddToSetStrategy;
protected final DestroyNodeStrategy destroyNodeStrategy; private final RebootNodeStrategy rebootNodeStrategy;
protected final ResumeNodeStrategy resumeNodeStrategy; private final DestroyNodeStrategy destroyNodeStrategy;
protected final SuspendNodeStrategy suspendNodeStrategy; private final ResumeNodeStrategy resumeNodeStrategy;
protected final Provider<TemplateBuilder> templateBuilderProvider; private final SuspendNodeStrategy suspendNodeStrategy;
protected final Provider<TemplateOptions> templateOptionsProvider; private final Provider<TemplateBuilder> templateBuilderProvider;
protected final Predicate<NodeMetadata> nodeRunning; private final Provider<TemplateOptions> templateOptionsProvider;
protected final Predicate<NodeMetadata> nodeTerminated; private final Predicate<NodeMetadata> nodeRunning;
protected final Predicate<NodeMetadata> nodeSuspended; private final Predicate<NodeMetadata> nodeTerminated;
protected final ComputeUtils utils; private final Predicate<NodeMetadata> nodeSuspended;
protected final Timeouts timeouts; private final RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory statementRunner;
protected final ExecutorService executor; private final Timeouts timeouts;
private final ExecutorService executor;
@Inject @Inject
protected BaseComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore, protected BaseComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore,
@ -134,7 +139,8 @@ public class BaseComputeService implements ComputeService {
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider, Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider,
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning, @Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning,
@Named("NODE_TERMINATED") Predicate<NodeMetadata> nodeTerminated, @Named("NODE_TERMINATED") Predicate<NodeMetadata> nodeTerminated,
@Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended, ComputeUtils utils, Timeouts timeouts, @Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended,
RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory statementRunner, Timeouts timeouts,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) { @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
this.context = checkNotNull(context, "context"); this.context = checkNotNull(context, "context");
this.credentialStore = checkNotNull(credentialStore, "credentialStore"); this.credentialStore = checkNotNull(credentialStore, "credentialStore");
@ -153,7 +159,7 @@ public class BaseComputeService implements ComputeService {
this.nodeRunning = checkNotNull(nodeRunning, "nodeRunning"); this.nodeRunning = checkNotNull(nodeRunning, "nodeRunning");
this.nodeTerminated = checkNotNull(nodeTerminated, "nodeTerminated"); this.nodeTerminated = checkNotNull(nodeTerminated, "nodeTerminated");
this.nodeSuspended = checkNotNull(nodeSuspended, "nodeSuspended"); this.nodeSuspended = checkNotNull(nodeSuspended, "nodeSuspended");
this.utils = checkNotNull(utils, "utils"); this.statementRunner = checkNotNull(statementRunner, "statementRunner");
this.timeouts = checkNotNull(timeouts, "timeouts"); this.timeouts = checkNotNull(timeouts, "timeouts");
this.executor = checkNotNull(executor, "executor"); this.executor = checkNotNull(executor, "executor");
} }
@ -177,17 +183,20 @@ public class BaseComputeService implements ComputeService {
logger.debug(">> running %d node%s tag(%s) location(%s) image(%s) hardwareProfile(%s) options(%s)", count, logger.debug(">> running %d node%s tag(%s) location(%s) image(%s) hardwareProfile(%s) options(%s)", count,
count > 1 ? "s" : "", tag, template.getLocation().getId(), template.getImage().getId(), template count > 1 ? "s" : "", tag, template.getLocation().getId(), template.getImage().getId(), template
.getHardware().getId(), template.getOptions()); .getHardware().getId(), template.getOptions());
Set<NodeMetadata> nodes = newHashSet(); Set<NodeMetadata> goodNodes = newLinkedHashSet();
Map<NodeMetadata, Exception> badNodes = newLinkedHashMap(); Map<NodeMetadata, Exception> badNodes = newLinkedHashMap();
Map<?, Future<Void>> responses = runNodesAndAddToSetStrategy.execute(tag, count, template, nodes, badNodes); Multimap<NodeMetadata, CustomizationResponse> customizationResponses = LinkedHashMultimap.create();
Map<?, Exception> executionExceptions = awaitCompletion(responses, executor, null, logger, "resumeing nodes");
for (NodeMetadata node : concat(nodes, badNodes.keySet())) Map<?, Future<Void>> responses = runNodesAndAddToSetStrategy.execute(tag, count, template, goodNodes, badNodes,
customizationResponses);
Map<?, Exception> executionExceptions = awaitCompletion(responses, executor, null, logger, "resuming nodes");
for (NodeMetadata node : concat(goodNodes, badNodes.keySet()))
if (node.getCredentials() != null) if (node.getCredentials() != null)
credentialStore.put("node#" + node.getId(), node.getCredentials()); credentialStore.put("node#" + node.getId(), node.getCredentials());
if (executionExceptions.size() > 0 || badNodes.size() > 0) { if (executionExceptions.size() > 0 || badNodes.size() > 0) {
throw new RunNodesException(tag, count, template, nodes, executionExceptions, badNodes); throw new RunNodesException(tag, count, template, goodNodes, executionExceptions, badNodes);
} }
return nodes; return goodNodes;
} }
/** /**
@ -436,47 +445,54 @@ public class BaseComputeService implements ComputeService {
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public Map<NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter, public Map<NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter, Payload runScript,
final Payload runScript, @Nullable final RunScriptOptions options) throws RunScriptOnNodesException { @Nullable RunScriptOptions options) throws RunScriptOnNodesException {
try {
return runScriptOnNodesMatching(filter, Statements.exec(Strings2.toStringAndClose(checkNotNull(runScript,
"runScript").getInput())), options);
} catch (IOException e) {
Throwables.propagate(e);
return null;
}
}
/**
* {@inheritDoc}
*/
@Override
public Map<NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter, String runScript,
@Nullable 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,
@Nullable RunScriptOptions options) throws RunScriptOnNodesException {
checkNotNull(filter, "Filter must be provided"); checkNotNull(filter, "Filter must be provided");
checkNotNull(runScript, "runScript"); checkNotNull(runScript, "runScript");
checkNotNull(options, "options"); checkNotNull(options, "options");
if (options.getTaskName() == null)
options.nameTask("jclouds-script-" + System.currentTimeMillis());
Iterable<? extends NodeMetadata> nodes = filter(detailsOnAllNodes(), filter); Iterable<? extends NodeMetadata> nodes = filter(detailsOnAllNodes(), filter);
final Map<NodeMetadata, ExecResponse> execs = newHashMap(); Map<NodeMetadata, ExecResponse> goodNodes = newLinkedHashMap();
final Map<NodeMetadata, Future<Void>> responses = newHashMap(); Map<NodeMetadata, Exception> badNodes = newLinkedHashMap();
final Map<NodeMetadata, Exception> badNodes = newLinkedHashMap();
Map<NodeMetadata, Future<Void>> responses = newLinkedHashMap();
nodes = filterNodesWhoCanRunScripts(nodes, badNodes, options.getOverrideCredentials()); nodes = filterNodesWhoCanRunScripts(nodes, badNodes, options.getOverrideCredentials());
for (final NodeMetadata node : nodes) { for (NodeMetadata node : nodes) {
responses.put(node, executor.submit(statementRunner.create(node, runScript, options, goodNodes, badNodes)));
responses.put(node, executor.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
try {
ExecResponse response = utils.runScriptOnNode(node, Statements.exec(Strings2.toStringAndClose(runScript
.getInput())), options);
if (response != null)
execs.put(node, response);
} catch (Exception e) {
badNodes.put(node, e);
}
return null;
} }
}));
}
Map<?, Exception> exceptions = awaitCompletion(responses, executor, null, logger, "running script on nodes"); Map<?, Exception> exceptions = awaitCompletion(responses, executor, null, logger, "running script on nodes");
if (exceptions.size() > 0 || badNodes.size() > 0) { if (exceptions.size() > 0 || badNodes.size() > 0) {
throw new RunScriptOnNodesException(runScript, options, execs, exceptions, badNodes); throw new RunScriptOnNodesException(runScript, options, goodNodes, exceptions, badNodes);
} }
return goodNodes;
return execs;
} }

View File

@ -0,0 +1,162 @@
/**
*
* Copyright (C) 2010 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.compute.strategy;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Throwables.getRootCause;
import static org.jclouds.compute.util.ComputeServiceUtils.findReachableSocketOnNode;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import javax.annotation.Nullable;
import javax.annotation.Resource;
import javax.inject.Named;
import org.jclouds.compute.callables.StartInitScriptOnNode;
import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
import org.jclouds.logging.Logger;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.ssh.ExecResponse;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Multimap;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
/**
*
* @author Adrian Cole
*/
public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Callable<Void>,
Function<NodeMetadata, Void> {
public static interface Factory {
Callable<Void> create(TemplateOptions options, NodeMetadata node, Set<NodeMetadata> goodNodes,
Map<NodeMetadata, Exception> badNodes,
Multimap<NodeMetadata, CustomizationResponse> customizationResponses);
Function<NodeMetadata, Void> create(TemplateOptions options, Set<NodeMetadata> goodNodes,
Map<NodeMetadata, Exception> badNodes,
Multimap<NodeMetadata, CustomizationResponse> customizationResponses);
}
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
private final Predicate<NodeMetadata> nodeRunning;
private final ScriptInvokerForNodeAndStatement scriptInvokerForNodeAndStatement;
private final GetNodeMetadataStrategy getNode;
private final RetryIfSocketNotYetOpen socketTester;
private final Timeouts timeouts;
@Nullable
private final Statement statement;
private final TemplateOptions options;
private NodeMetadata node;
private final Set<NodeMetadata> goodNodes;
private final Map<NodeMetadata, Exception> badNodes;
private final Multimap<NodeMetadata, CustomizationResponse> customizationResponses;
private transient boolean tainted;
@AssistedInject
public CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning, GetNodeMetadataStrategy getNode,
RetryIfSocketNotYetOpen socketTester, Timeouts timeouts,
Function<TemplateOptions, Statement> templateOptionsToStatement,
ScriptInvokerForNodeAndStatement scriptInvokerForNodeAndStatement, @Assisted TemplateOptions options,
@Assisted @Nullable NodeMetadata node, @Assisted Set<NodeMetadata> goodNodes,
@Assisted Map<NodeMetadata, Exception> badNodes,
@Assisted Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
this.statement = checkNotNull(templateOptionsToStatement, "templateOptionsToStatement").apply(
checkNotNull(options, "options"));
this.nodeRunning = checkNotNull(nodeRunning, "nodeRunning");
this.scriptInvokerForNodeAndStatement = checkNotNull(scriptInvokerForNodeAndStatement,
"scriptInvokerForNodeAndStatement");
this.getNode = checkNotNull(getNode, "getNode");
this.socketTester = checkNotNull(socketTester, "socketTester");
this.timeouts = checkNotNull(timeouts, "timeouts");
this.node = node;
this.options = checkNotNull(options, "options");
this.goodNodes = checkNotNull(goodNodes, "goodNodes");
this.badNodes = checkNotNull(badNodes, "badNodes");
this.customizationResponses = checkNotNull(customizationResponses, "customizationResponses");
}
@AssistedInject
public CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning, GetNodeMetadataStrategy getNode,
RetryIfSocketNotYetOpen socketTester, Timeouts timeouts,
Function<TemplateOptions, Statement> templateOptionsToStatement,
ScriptInvokerForNodeAndStatement scriptInvokerForNodeAndStatement, @Assisted TemplateOptions options,
@Assisted Set<NodeMetadata> goodNodes, @Assisted Map<NodeMetadata, Exception> badNodes,
@Assisted Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
this(nodeRunning, getNode, socketTester, timeouts, templateOptionsToStatement, scriptInvokerForNodeAndStatement,
options, null, goodNodes, badNodes, customizationResponses);
}
@Override
public Void call() {
checkState(!tainted, "this object is not designed to be reused: %s", toString());
tainted = true;
try {
if (options.shouldBlockUntilRunning()) {
if (nodeRunning.apply(node)) {
node = getNode.getNode(node.getId());
} else {
throw new IllegalStateException(String.format(
"node didn't achieve the state running on node %s within %d seconds, final state: %s", node
.getId(), timeouts.nodeRunning / 1000, node.getState()));
}
if (statement != null) {
StartInitScriptOnNode scriptInstructions = scriptInvokerForNodeAndStatement.create(node, statement,
options);
ExecResponse exec = scriptInstructions.call();
customizationResponses.put(node, exec);
}
if (options.getPort() > 0) {
findReachableSocketOnNode(socketTester.seconds(options.getSeconds()), node, options.getPort());
}
}
logger.debug("<< options applied node(%s)", node.getId());
goodNodes.add(node);
} catch (Exception e) {
logger.error(e, "<< problem applying options to node(%s): ", node.getId(), getRootCause(e).getMessage());
badNodes.put(node, e);
}
return null;
}
@Override
public Void apply(NodeMetadata input) {
this.node = input;
call();
return null;
}
}

View File

@ -21,12 +21,14 @@ package org.jclouds.compute.strategy;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Future;
import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.strategy.impl.EncodeTagIntoNameRunNodesAndAddToSetStrategy; import org.jclouds.compute.strategy.impl.EncodeTagIntoNameRunNodesAndAddToSetStrategy;
import java.util.concurrent.Future; import com.google.common.collect.Multimap;
import com.google.inject.ImplementedBy; import com.google.inject.ImplementedBy;
/** /**
@ -37,6 +39,6 @@ import com.google.inject.ImplementedBy;
@ImplementedBy(EncodeTagIntoNameRunNodesAndAddToSetStrategy.class) @ImplementedBy(EncodeTagIntoNameRunNodesAndAddToSetStrategy.class)
public interface RunNodesAndAddToSetStrategy { public interface RunNodesAndAddToSetStrategy {
Map<?, Future<Void>> execute(String tag, int count, Template template, Map<?, Future<Void>> execute(String tag, int count, Template template, Set<NodeMetadata> goodNodes,
Set<NodeMetadata> nodes, Map<NodeMetadata, Exception> badNodes); Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses);
} }

View File

@ -0,0 +1,108 @@
/**
*
* Copyright (C) 2010 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.compute.strategy;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Throwables.getRootCause;
import java.util.Map;
import java.util.concurrent.Callable;
import javax.annotation.Nullable;
import javax.annotation.Resource;
import javax.inject.Named;
import org.jclouds.compute.callables.StartInitScriptOnNode;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.ssh.ExecResponse;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
/**
*
* @author Adrian Cole
*/
public class RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Callable<Void> {
public static interface Factory {
Callable<Void> create(NodeMetadata node, Statement statement, RunScriptOptions options,
Map<NodeMetadata, ExecResponse> goodNodes, Map<NodeMetadata, Exception> badNodes);
}
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
// NOTE this is mutable
protected NodeMetadata node;
private final Map<NodeMetadata, Exception> badNodes;
private final Map<NodeMetadata, ExecResponse> goodNodes;
private final RunScriptOptions options;
protected final Statement statement;
private final ScriptInvokerForNodeAndStatement scriptInvokerForNodeAndStatement;
private transient boolean tainted;
@AssistedInject
public RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap(
ScriptInvokerForNodeAndStatement scriptInvokerForNodeAndStatement, @Assisted NodeMetadata node,
@Assisted @Nullable Statement statement, @Assisted RunScriptOptions options,
@Assisted Map<NodeMetadata, ExecResponse> goodNodes, @Assisted Map<NodeMetadata, Exception> badNodes) {
this.statement = checkNotNull(statement, "statement");
this.scriptInvokerForNodeAndStatement = checkNotNull(scriptInvokerForNodeAndStatement,
"scriptInvokerForNodeAndStatement");
this.node = node;
this.badNodes = checkNotNull(badNodes, "badNodes");
this.goodNodes = checkNotNull(goodNodes, "goodNodes");
this.options = checkNotNull(options, "options");
}
@AssistedInject
public RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap(
ScriptInvokerForNodeAndStatement scriptInvokerForNodeAndStatement, @Assisted @Nullable Statement statement,
@Assisted RunScriptOptions options, @Assisted Map<NodeMetadata, ExecResponse> goodNodes,
@Assisted Map<NodeMetadata, Exception> badNodes) {
this(scriptInvokerForNodeAndStatement, null, statement, options, goodNodes, badNodes);
}
@Override
public Void call() {
checkState(node != null, "node must be set");
checkState(!tainted, "this object is not designed to be reused: %s", toString());
tainted = true;
try {
StartInitScriptOnNode scriptInstructions = scriptInvokerForNodeAndStatement.create(node, statement, options);
ExecResponse exec = scriptInstructions.call();
logger.trace("<< script output for node(%s): %s", node.getId(), exec);
logger.debug("<< options applied node(%s)", node.getId());
goodNodes.put(node, exec);
} catch (Exception e) {
logger.error(e, "<< problem applying options to node(%s): ", node.getId(), getRootCause(e).getMessage());
badNodes.put(node, e);
}
return null;
}
}

View File

@ -0,0 +1,56 @@
/**
*
* Copyright (C) 2010 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.compute.strategy;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Singleton;
import org.jclouds.compute.callables.StartInitScriptOnNode;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.scriptbuilder.domain.Statement;
import com.google.inject.Inject;
/**
*
* @author Adrian Cole
*/
@Singleton
public class ScriptInvokerForNodeAndStatement {
private final StartInitScriptOnNode.Factory initAndStartScriptOnNodeFactory;
@Inject
public ScriptInvokerForNodeAndStatement(StartInitScriptOnNode.Factory initAndStartScriptOnNodeFactory) {
this.initAndStartScriptOnNodeFactory = checkNotNull(initAndStartScriptOnNodeFactory,
"initAndStartScriptOnNodeFactory");
}
public StartInitScriptOnNode create(NodeMetadata node, Statement runScript, RunScriptOptions options) {
checkNotNull(node, "node");
checkNotNull(runScript, "runScript");
checkNotNull(options, "options");
return options.shouldBlockOnComplete() ? initAndStartScriptOnNodeFactory.blockOnComplete(node, options
.getTaskName(), runScript, options.shouldRunAsRoot()) : initAndStartScriptOnNodeFactory
.dontBlockOnComplete(node, options.getTaskName(), runScript, options.shouldRunAsRoot());
}
}

View File

@ -19,6 +19,13 @@
package org.jclouds.compute.strategy.impl; package org.jclouds.compute.strategy.impl;
import static com.google.common.base.Objects.toStringHelper;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.any;
import static com.google.common.collect.Maps.newLinkedHashMap;
import static com.google.common.collect.Sets.newLinkedHashSet;
import static org.jclouds.concurrent.Futures.compose;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -32,20 +39,19 @@ import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.strategy.AddNodeWithTagStrategy; import org.jclouds.compute.strategy.AddNodeWithTagStrategy;
import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import org.jclouds.compute.strategy.ListNodesStrategy; import org.jclouds.compute.strategy.ListNodesStrategy;
import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy; import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy;
import org.jclouds.compute.util.ComputeUtils;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.Iterables; import com.google.common.collect.Multimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
/** /**
* creates futures that correlate to * creates futures that correlate to
@ -54,24 +60,54 @@ import com.google.common.collect.Sets;
*/ */
@Singleton @Singleton
public class EncodeTagIntoNameRunNodesAndAddToSetStrategy implements RunNodesAndAddToSetStrategy { public class EncodeTagIntoNameRunNodesAndAddToSetStrategy implements RunNodesAndAddToSetStrategy {
private class AddNode implements Callable<NodeMetadata> {
private final String name;
private final String tag;
private final Template template;
private AddNode(String name, String tag, Template template) {
this.name = checkNotNull(name, "name");
this.tag = checkNotNull(tag, "tag");
this.template = checkNotNull(template, "template");
}
@Override
public NodeMetadata call() throws Exception {
NodeMetadata node = null;
logger.debug(">> starting node(%s) tag(%s)", name, tag);
node = addNodeWithTagStrategy.addNodeWithTag(tag, name, template);
logger.debug("<< %s node(%s)", node.getState(), node.getId());
return node;
}
public String toString() {
return toStringHelper(this).add("name", name).add("tag", tag).add("template", template).toString();
}
}
@Resource @Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER) @Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
protected final AddNodeWithTagStrategy addNodeWithTagStrategy; protected final AddNodeWithTagStrategy addNodeWithTagStrategy;
protected final ListNodesStrategy listNodesStrategy; protected final ListNodesStrategy listNodesStrategy;
protected final String nodeNamingConvention; protected final String nodeNamingConvention;
protected final ComputeUtils utils;
protected final ExecutorService executor; protected final ExecutorService executor;
protected final CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory;
@Inject @Inject
protected EncodeTagIntoNameRunNodesAndAddToSetStrategy(AddNodeWithTagStrategy addNodeWithTagStrategy, protected EncodeTagIntoNameRunNodesAndAddToSetStrategy(
ListNodesStrategy listNodesStrategy, @Named("NAMING_CONVENTION") String nodeNamingConvention, AddNodeWithTagStrategy addNodeWithTagStrategy,
ComputeUtils utils, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) { ListNodesStrategy listNodesStrategy,
@Named("NAMING_CONVENTION") String nodeNamingConvention,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor,
CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory) {
this.addNodeWithTagStrategy = addNodeWithTagStrategy; this.addNodeWithTagStrategy = addNodeWithTagStrategy;
this.listNodesStrategy = listNodesStrategy; this.listNodesStrategy = listNodesStrategy;
this.nodeNamingConvention = nodeNamingConvention; this.nodeNamingConvention = nodeNamingConvention;
this.utils = utils;
this.executor = executor; this.executor = executor;
this.customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory = customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory;
} }
/** /**
@ -79,22 +115,13 @@ public class EncodeTagIntoNameRunNodesAndAddToSetStrategy implements RunNodesAnd
* simultaneously runs the nodes and applies options to them. * simultaneously runs the nodes and applies options to them.
*/ */
@Override @Override
public Map<?, Future<Void>> execute(final String tag, final int count, final Template template, public Map<?, Future<Void>> execute(String tag, int count, Template template, Set<NodeMetadata> goodNodes,
final Set<NodeMetadata> nodes, final Map<NodeMetadata, Exception> badNodes) { Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
Map<String, Future<Void>> responses = Maps.newHashMap(); Map<String, Future<Void>> responses = newLinkedHashMap();
for (final String name : getNextNames(tag, template, count)) { for (String name : getNextNames(tag, template, count)) {
responses.put(name, executor.submit(new Callable<Void>() { responses.put(name, compose(executor.submit(new AddNode(name, tag, template)),
@Override customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory.create(template.getOptions(),
public Void call() throws Exception { goodNodes, badNodes, customizationResponses), executor));
NodeMetadata node = null;
logger.debug(">> starting node(%s) tag(%s)", name, tag);
node = addNodeWithTagStrategy.addNodeWithTag(tag, name, template);
logger.debug("<< %s node(%s)", node.getState(), node.getId());
utils.runOptionsOnNodeAndAddToGoodSetOrPutExceptionIntoBadMap(node, badNodes, nodes,
template.getOptions()).call();
return null;
}
}));
} }
return responses; return responses;
} }
@ -110,13 +137,13 @@ public class EncodeTagIntoNameRunNodesAndAddToSetStrategy implements RunNodesAnd
* @return * @return
*/ */
protected Set<String> getNextNames(final String tag, final Template template, int count) { protected Set<String> getNextNames(final String tag, final Template template, int count) {
Set<String> names = Sets.newHashSet(); Set<String> names = newLinkedHashSet();
Iterable<? extends ComputeMetadata> currentNodes = listNodesStrategy.listNodes(); Iterable<? extends ComputeMetadata> currentNodes = listNodesStrategy.listNodes();
int maxTries = 100; int maxTries = 100;
int currentTries = 0; int currentTries = 0;
while (names.size() < count && currentTries++ < maxTries) { while (names.size() < count && currentTries++ < maxTries) {
final String name = getNextName(tag, template); final String name = getNextName(tag, template);
if (!Iterables.any(currentNodes, new Predicate<ComputeMetadata>() { if (!any(currentNodes, new Predicate<ComputeMetadata>() {
@Override @Override
public boolean apply(ComputeMetadata input) { public boolean apply(ComputeMetadata input) {

View File

@ -31,12 +31,14 @@ import static org.jclouds.scriptbuilder.domain.Statements.pipeHttpResponseToBash
import java.net.URI; import java.net.URI;
import java.util.Formatter; import java.util.Formatter;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.concurrent.Callable; import java.util.Map.Entry;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.annotation.Resource;
import javax.inject.Named;
import org.jclouds.compute.ComputeServiceContextBuilder; import org.jclouds.compute.ComputeServiceContextBuilder;
import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Hardware;
@ -45,13 +47,13 @@ import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.Processor; import org.jclouds.compute.domain.Processor;
import org.jclouds.compute.domain.Volume; import org.jclouds.compute.domain.Volume;
import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen; import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.net.IPSocket; import org.jclouds.net.IPSocket;
import org.jclouds.rest.Providers; import org.jclouds.rest.Providers;
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.ssh.SshClient;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
@ -104,9 +106,23 @@ public class ComputeServiceUtils {
return extractZipIntoDirectory(new HttpRequest("GET", zip), directory); return extractZipIntoDirectory(new HttpRequest("GET", zip), directory);
} }
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected static Logger logger = Logger.NULL;
/**
*
*
* @return NOTAG#+from if tag cannot be parsed
*/
public static String parseTagFromName(String from) { public static String parseTagFromName(String from) {
Matcher matcher = DELIMETED_BY_HYPHEN_ENDING_IN_HYPHEN_HEX.matcher(from); Matcher matcher = DELIMETED_BY_HYPHEN_ENDING_IN_HYPHEN_HEX.matcher(from);
return matcher.find() ? matcher.group(1) : "NOTAG#" + from; String returnVal = matcher.find() ? matcher.group(1) : "NOTAG#" + from;
if (logger.isTraceEnabled()) {
if (returnVal.startsWith("NOTAG#"))
logger.trace("failed to parse tag from name %s", from);
}
return returnVal;
} }
public static double getCores(Hardware input) { public static double getCores(Hardware input) {
@ -147,8 +163,8 @@ public class ComputeServiceUtils {
Formatter fmt = new Formatter().format("Execution failures:%n%n"); Formatter fmt = new Formatter().format("Execution failures:%n%n");
int index = 1; int index = 1;
for (Entry<?, Exception> errorMessage : executionExceptions.entrySet()) { for (Entry<?, Exception> errorMessage : executionExceptions.entrySet()) {
fmt.format("%s) %s on %s:%n%s%n%n", index++, errorMessage.getValue().getClass().getSimpleName(), fmt.format("%s) %s on %s:%n%s%n%n", index++, errorMessage.getValue().getClass().getSimpleName(), errorMessage
errorMessage.getKey(), getStackTraceAsString(errorMessage.getValue())); .getKey(), getStackTraceAsString(errorMessage.getValue()));
} }
return fmt.format("%s error[s]", executionExceptions.size()).toString(); return fmt.format("%s error[s]", executionExceptions.size()).toString();
} }
@ -173,12 +189,6 @@ public class ComputeServiceUtils {
}); });
} }
public static interface SshCallable<T> extends Callable<T> {
NodeMetadata getNode();
void setConnection(SshClient ssh, Logger logger);
}
public static Iterable<String> getSupportedProviders() { public static Iterable<String> getSupportedProviders() {
return Providers.getSupportedProvidersOfType(ComputeServiceContextBuilder.class); return Providers.getSupportedProvidersOfType(ComputeServiceContextBuilder.class);
} }
@ -188,8 +198,7 @@ public class ComputeServiceUtils {
checkNodeHasIps(node); checkNodeHasIps(node);
IPSocket socket = null; IPSocket socket = null;
try { try {
socket = find( socket = find(transform(concat(node.getPublicAddresses(), node.getPrivateAddresses()),
transform(concat(node.getPublicAddresses(), node.getPrivateAddresses()),
new Function<String, IPSocket>() { new Function<String, IPSocket>() {
@Override @Override

View File

@ -19,53 +19,24 @@
package org.jclouds.compute.util; package org.jclouds.compute.util;
import static com.google.common.base.Throwables.getRootCause; import static com.google.common.collect.Maps.newLinkedHashMap;
import static com.google.common.base.Throwables.propagate;
import static com.google.common.collect.Iterables.size;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
import static org.jclouds.compute.util.ComputeServiceUtils.findReachableSocketOnNode;
import static org.jclouds.concurrent.FutureIterables.awaitCompletion;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import javax.annotation.Nullable; import javax.inject.Inject;
import javax.annotation.Resource;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.compute.callables.InitAndStartScriptOnNode; import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.callables.RunScriptOnNode;
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.TemplateOptions; import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen; import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import org.jclouds.compute.predicates.ScriptStatusReturnsZero.CommandUsingClient;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import org.jclouds.compute.util.ComputeServiceUtils.SshCallable;
import org.jclouds.logging.Logger;
import org.jclouds.scriptbuilder.InitBuilder;
import org.jclouds.scriptbuilder.domain.AuthorizeRSAPublicKey;
import org.jclouds.scriptbuilder.domain.InstallRSAPrivateKey;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.StatementList;
import org.jclouds.ssh.ExecResponse;
import org.jclouds.ssh.SshClient;
import com.google.common.base.Function; import com.google.common.collect.Multimap;
import com.google.common.base.Predicate;
import com.google.inject.Inject;
/** /**
* *
@ -73,168 +44,26 @@ import com.google.inject.Inject;
*/ */
@Singleton @Singleton
public class ComputeUtils { public class ComputeUtils {
@Resource private final CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory;
@Named(ComputeServiceConstants.COMPUTE_LOGGER) private final ExecutorService executor;
protected Logger logger = Logger.NULL;
protected final Function<NodeMetadata, SshClient> sshFactory;
protected final Predicate<CommandUsingClient> runScriptNotRunning;
protected final Provider<RetryIfSocketNotYetOpen> socketTester;
protected final ExecutorService executor;
protected final Predicate<NodeMetadata> nodeRunning;
protected final GetNodeMetadataStrategy getNode;
protected final Timeouts timeouts;
@Inject @Inject
public ComputeUtils(Provider<RetryIfSocketNotYetOpen> socketTester, Function<NodeMetadata, SshClient> sshFactory, public ComputeUtils(
@Named("SCRIPT_COMPLETE") Predicate<CommandUsingClient> runScriptNotRunning, GetNodeMetadataStrategy getNode, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory,
Timeouts timeouts, @Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) { @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
this.sshFactory = sshFactory; this.customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory = customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory;
this.nodeRunning = nodeRunning;
this.timeouts = timeouts;
this.getNode = getNode;
this.socketTester = socketTester;
this.runScriptNotRunning = runScriptNotRunning;
this.executor = executor; this.executor = executor;
} }
public Map<?, Future<Void>> runOptionsOnNodesAndAddToGoodSetOrPutExceptionIntoBadMap(final TemplateOptions options, public Map<?, Future<Void>> customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(TemplateOptions options,
Iterable<NodeMetadata> runningNodes, final Set<NodeMetadata> goodNodes, Iterable<NodeMetadata> runningNodes, Set<NodeMetadata> goodNodes, Map<NodeMetadata, Exception> badNodes,
final Map<NodeMetadata, Exception> badNodes) { Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
Map<NodeMetadata, Future<Void>> responses = newHashMap(); Map<NodeMetadata, Future<Void>> responses = newLinkedHashMap();
for (final NodeMetadata node : runningNodes) { for (NodeMetadata node : runningNodes) {
responses.put(node, executor.submit(runOptionsOnNodeAndAddToGoodSetOrPutExceptionIntoBadMap(node, badNodes, responses.put(node, executor.submit(customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory.create(
goodNodes, options))); options, node, goodNodes, badNodes, customizationResponses)));
} }
return responses; return responses;
} }
public Callable<Void> runOptionsOnNodeAndAddToGoodSetOrPutExceptionIntoBadMap(final NodeMetadata node,
final Map<NodeMetadata, Exception> badNodes, final Set<NodeMetadata> goodNodes, final TemplateOptions options) {
return new Callable<Void>() {
@Override
public Void call() throws Exception {
try {
NodeMetadata node1 = runOptionsOnNode(node, options);
logger.debug("<< options applied node(%s)", node1.getId());
goodNodes.add(node1);
} catch (Exception e) {
logger.error(e, "<< problem applying options to node(%s): ", node.getId(), getRootCause(e).getMessage());
badNodes.put(node, e);
}
return null;
}
};
}
public NodeMetadata runOptionsOnNode(NodeMetadata node, TemplateOptions options) {
if (!options.shouldBlockUntilRunning())
return node;
if (nodeRunning.apply(node))
node = NodeMetadataBuilder.fromNodeMetadata(getNode.getNode(node.getId())).credentials(node.getCredentials())
.build();
else
throw new IllegalStateException(String.format(
"node didn't achieve the state running on node %s within %d seconds, final state: %s", node.getId(),
timeouts.nodeRunning / 1000, node.getState()));
List<Statement> bootstrap = newArrayList();
if (options.getPublicKey() != null)
bootstrap.add(new AuthorizeRSAPublicKey(options.getPublicKey()));
if (options.getRunScript() != null)
bootstrap.add(options.getRunScript());
if (options.getPrivateKey() != null)
bootstrap.add(new InstallRSAPrivateKey(options.getPrivateKey()));
if (bootstrap.size() >= 1) {
if (options.getTaskName() == null && !(options.getRunScript() instanceof InitBuilder))
options.nameTask("bootstrap");
runScriptOnNode(node, bootstrap.size() == 1 ? bootstrap.get(0) : new StatementList(bootstrap), options);
}
return node;
}
public ExecResponse runScriptOnNode(NodeMetadata node, Statement runScript, RunScriptOptions options) {
InitAndStartScriptOnNode callable = generateScript(node, runScript, options);
ExecResponse response;
SshClient ssh = sshFactory.apply(node);
try {
ssh.connect();
callable.setConnection(ssh, logger);
response = callable.call();
} finally {
if (ssh != null)
ssh.disconnect();
}
if (options.getPort() > 0) {
findReachableSocketOnNode(socketTester.get().seconds(options.getSeconds()), node, options.getPort());
}
return response;
}
public InitAndStartScriptOnNode generateScript(NodeMetadata node, Statement script, RunScriptOptions options) {
return options.shouldBlockOnComplete() ? new RunScriptOnNode(runScriptNotRunning, node, options.getTaskName(),
script, options.shouldRunAsRoot()) : new InitAndStartScriptOnNode(node, options.getTaskName(), script,
options.shouldRunAsRoot());
}
public Map<SshCallable<?>, ?> runCallablesOnNode(NodeMetadata node, Iterable<SshCallable<?>> parallel,
@Nullable SshCallable<?> last) {
SshClient ssh = sshFactory.apply(node);
try {
ssh.connect();
return runTasksUsingSshClient(parallel, last, ssh);
} finally {
if (ssh != null)
ssh.disconnect();
}
}
private Map<SshCallable<?>, ?> runTasksUsingSshClient(Iterable<SshCallable<?>> parallel, SshCallable<?> last,
SshClient ssh) {
Map<SshCallable<?>, Object> responses = newHashMap();
if (size(parallel) > 0) {
responses.putAll(runCallablesUsingSshClient(parallel, ssh));
}
if (last != null) {
last.setConnection(ssh, logger);
try {
responses.put(last, last.call());
} catch (Exception e) {
propagate(e);
}
}
return responses;
}
// TODO refactor
private Map<SshCallable<?>, Object> runCallablesUsingSshClient(Iterable<SshCallable<?>> parallel, SshClient ssh) {
Map<SshCallable<?>, Future<?>> parallelResponses = newHashMap();
for (SshCallable<?> callable : parallel) {
callable.setConnection(ssh, logger);
parallelResponses.put(callable, executor.submit(callable));
}
Map<SshCallable<?>, Exception> exceptions = awaitCompletion(parallelResponses, executor, null, logger, "ssh");
if (exceptions.size() > 0)
throw new RuntimeException(String.format("error invoking callables on nodes: %s", exceptions));
Map<SshCallable<?>, Object> newresponses = transform(parallelResponses);
return newresponses;
}
@SuppressWarnings("unchecked")
public <T> Map<SshCallable<?>, T> transform(Map<SshCallable<?>, Future<?>> responses) {
Map<SshCallable<?>, T> actualResponses = newHashMap();
for (Map.Entry<SshCallable<?>, Future<?>> entry : responses.entrySet()) {
try {
actualResponses.put(entry.getKey(), (T) entry.getValue().get());
} catch (InterruptedException e) {
throw propagate(e);
} catch (ExecutionException e) {
throw propagate(e);
}
}
return actualResponses;
}
} }

View File

@ -19,10 +19,12 @@
package org.jclouds.ssh; package org.jclouds.ssh;
import org.jclouds.compute.config.CustomizationResponse;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
public class ExecResponse { public class ExecResponse implements CustomizationResponse {
private final String error; private final String error;
private final String output; private final String output;

View File

@ -38,7 +38,6 @@ import static org.jclouds.compute.predicates.NodePredicates.all;
import static org.jclouds.compute.predicates.NodePredicates.runningWithTag; import static org.jclouds.compute.predicates.NodePredicates.runningWithTag;
import static org.jclouds.compute.predicates.NodePredicates.withTag; import static org.jclouds.compute.predicates.NodePredicates.withTag;
import static org.jclouds.compute.util.ComputeServiceUtils.getCores; import static org.jclouds.compute.util.ComputeServiceUtils.getCores;
import static org.jclouds.io.Payloads.newStringPayload;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNotNull;
@ -75,7 +74,6 @@ import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.predicates.SocketOpen; import org.jclouds.predicates.SocketOpen;
import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.RestContextFactory; import org.jclouds.rest.RestContextFactory;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.ssh.ExecResponse; import org.jclouds.ssh.ExecResponse;
import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshClient;
import org.jclouds.ssh.SshException; import org.jclouds.ssh.SshException;
@ -159,8 +157,8 @@ public abstract class BaseComputeServiceLiveTest {
if (context != null) if (context != null)
context.close(); context.close();
Properties props = setupProperties(); Properties props = setupProperties();
context = new ComputeServiceContextFactory(getRestProperties()).createContext(provider, context = new ComputeServiceContextFactory(getRestProperties()).createContext(provider, ImmutableSet.of(
ImmutableSet.of(new Log4JLoggingModule(), getSshModule()), props); new Log4JLoggingModule(), getSshModule()), props);
client = context.getComputeService(); client = context.getComputeService();
} }
@ -180,8 +178,8 @@ public abstract class BaseComputeServiceLiveTest {
public void testCorrectAuthException() throws Exception { public void testCorrectAuthException() throws Exception {
ComputeServiceContext context = null; ComputeServiceContext context = null;
try { try {
context = new ComputeServiceContextFactory().createContext(provider, "MOMMA", "MIA", context = new ComputeServiceContextFactory().createContext(provider, "MOMMA", "MIA", ImmutableSet
ImmutableSet.<Module> of(new Log4JLoggingModule())); .<Module> of(new Log4JLoggingModule()));
context.getComputeService().listNodes(); context.getComputeService().listNodes();
} catch (AuthorizationException e) { } catch (AuthorizationException e) {
throw e; throw e;
@ -294,8 +292,8 @@ public abstract class BaseComputeServiceLiveTest {
protected void checkOsMatchesTemplate(NodeMetadata node) { protected void checkOsMatchesTemplate(NodeMetadata node) {
if (node.getOperatingSystem() != null) if (node.getOperatingSystem() != null)
assert node.getOperatingSystem().getFamily().equals(template.getImage().getOperatingSystem().getFamily()) : String assert node.getOperatingSystem().getFamily().equals(template.getImage().getOperatingSystem().getFamily()) : String
.format("expecting family %s but got %s", template.getImage().getOperatingSystem().getFamily(), .format("expecting family %s but got %s", template.getImage().getOperatingSystem().getFamily(), node
node.getOperatingSystem()); .getOperatingSystem());
} }
void assertLocationSameOrChild(Location test, Location expected) { void assertLocationSameOrChild(Location test, Location expected) {
@ -329,9 +327,8 @@ public abstract class BaseComputeServiceLiveTest {
protected Map<? extends NodeMetadata, ExecResponse> runScriptWithCreds(final String tag, OperatingSystem os, protected Map<? extends NodeMetadata, ExecResponse> runScriptWithCreds(final String tag, OperatingSystem os,
Credentials creds) throws RunScriptOnNodesException { Credentials creds) throws RunScriptOnNodesException {
try { try {
return client.runScriptOnNodesMatching(runningWithTag(tag), return client.runScriptOnNodesMatching(runningWithTag(tag), buildScript(os), overrideCredentialsWith(creds)
newStringPayload(buildScript(os).render(OsFamily.UNIX)), .nameTask("runScriptWithCreds"));
overrideCredentialsWith(creds).nameTask("runScriptWithCreds"));
} catch (SshException e) { } catch (SshException e) {
throw e; throw e;
} }
@ -361,8 +358,8 @@ public abstract class BaseComputeServiceLiveTest {
@Test(enabled = true, dependsOnMethods = "testCreateAnotherNodeWithANewContextToEnsureSharedMemIsntRequired") @Test(enabled = true, dependsOnMethods = "testCreateAnotherNodeWithANewContextToEnsureSharedMemIsntRequired")
public void testGet() throws Exception { public void testGet() throws Exception {
Map<String, ? extends NodeMetadata> metadataMap = newLinkedHashMap(uniqueIndex( Map<String, ? extends NodeMetadata> metadataMap = newLinkedHashMap(uniqueIndex(filter(client
filter(client.listNodesDetailsMatching(all()), and(withTag(tag), not(TERMINATED))), .listNodesDetailsMatching(all()), and(withTag(tag), not(TERMINATED))),
new Function<NodeMetadata, String>() { new Function<NodeMetadata, String>() {
@Override @Override
@ -453,7 +450,9 @@ public abstract class BaseComputeServiceLiveTest {
@Test(enabled = true, dependsOnMethods = { "testListNodes", "testGetNodesWithDetails" }) @Test(enabled = true, dependsOnMethods = { "testListNodes", "testGetNodesWithDetails" })
public void testDestroyNodes() { public void testDestroyNodes() {
client.destroyNodesMatching(withTag(tag)); int toDestroy = refreshNodes().size();
Set<? extends NodeMetadata> destroyed = client.destroyNodesMatching(withTag(tag));
assertEquals(toDestroy, destroyed.size());
for (NodeMetadata node : filter(client.listNodesDetailsMatching(all()), withTag(tag))) { for (NodeMetadata node : filter(client.listNodesDetailsMatching(all()), withTag(tag))) {
assert node.getState() == NodeState.TERMINATED : node; assert node.getState() == NodeState.TERMINATED : node;
assertEquals(context.getCredentialStore().get("node#" + node.getId()), null); assertEquals(context.getCredentialStore().get("node#" + node.getId()), null);

View File

@ -361,17 +361,17 @@ public class StubComputeServiceIntegrationTest extends BaseComputeServiceLiveTes
super.testTemplateMatch(); super.testTemplateMatch();
} }
@Override @Test(enabled = true, dependsOnMethods = "testSuspendResume")
public void testGetNodesWithDetails() throws Exception { public void testGetNodesWithDetails() throws Exception {
super.testGetNodesWithDetails(); super.testGetNodesWithDetails();
} }
@Override @Test(enabled = true, dependsOnMethods = "testSuspendResume")
public void testListNodes() throws Exception { public void testListNodes() throws Exception {
super.testListNodes(); super.testListNodes();
} }
@Override @Test(enabled = true, dependsOnMethods = { "testListNodes", "testGetNodesWithDetails" })
public void testDestroyNodes() { public void testDestroyNodes() {
super.testDestroyNodes(); super.testDestroyNodes();
} }

View File

@ -19,6 +19,7 @@
package org.jclouds.compute.util; package org.jclouds.compute.util;
import static org.jclouds.compute.util.ComputeServiceUtils.parseTagFromName;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.net.URI; import java.net.URI;
@ -38,6 +39,11 @@ import com.google.common.collect.ImmutableMultimap;
@Test(groups = "unit") @Test(groups = "unit")
public class ComputeServiceUtilsTest { public class ComputeServiceUtilsTest {
@Test
public void testParseTagFromName() {
assertEquals(parseTagFromName("gogrid--849"), "gogrid-");
}
@Test @Test
public void testExecHttpResponse() { public void testExecHttpResponse() {
HttpRequest request = new HttpRequest("GET", URI.create("https://adriancolehappy.s3.amazonaws.com/java/install"), HttpRequest request = new HttpRequest("GET", URI.create("https://adriancolehappy.s3.amazonaws.com/java/install"),

View File

@ -83,7 +83,6 @@ echo nameserver 208.67.222.222 >> /etc/resolv.conf
rm -rf /var/cache/apt /usr/lib/vmware-tools rm -rf /var/cache/apt /usr/lib/vmware-tools
echo "export PATH=\"\$JAVA_HOME/bin/:\$PATH\"" >> /root/.bashrc echo "export PATH=\"\$JAVA_HOME/bin/:\$PATH\"" >> /root/.bashrc
END_OF_SCRIPT END_OF_SCRIPT
# add runscript footer # add runscript footer

View File

@ -78,6 +78,11 @@
<artifactId>jersey-core</artifactId> <artifactId>jersey-core</artifactId>
<version>1.4</version> <version>1.4</version>
</dependency> </dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-assistedinject</artifactId>
<version>3.0-rc2</version>
</dependency>
<dependency> <dependency>
<groupId>com.google.inject</groupId> <groupId>com.google.inject</groupId>
<artifactId>guice</artifactId> <artifactId>guice</artifactId>

View File

@ -75,7 +75,7 @@ public class AWSEC2TemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest {
assertEquals(template.getImage().getOperatingSystem().getVersion(), "10.10"); assertEquals(template.getImage().getOperatingSystem().getVersion(), "10.10");
assertEquals(template.getImage().getOperatingSystem().is64Bit(), false); assertEquals(template.getImage().getOperatingSystem().is64Bit(), false);
assertEquals(template.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU); assertEquals(template.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU);
assertEquals(template.getImage().getVersion(), "20110115"); assertEquals(template.getImage().getVersion(), "20110122");
assertEquals(template.getImage().getUserMetadata().get("rootDeviceType"), "instance-store"); assertEquals(template.getImage().getUserMetadata().get("rootDeviceType"), "instance-store");
assertEquals(template.getLocation().getId(), "us-east-1"); assertEquals(template.getLocation().getId(), "us-east-1");
assertEquals(getCores(template.getHardware()), 1.0d); assertEquals(getCores(template.getHardware()), 1.0d);

View File

@ -31,7 +31,6 @@ public class SkaliCloudMalaysiaComputeServiceLiveTest extends ElasticStackComput
public SkaliCloudMalaysiaComputeServiceLiveTest() { public SkaliCloudMalaysiaComputeServiceLiveTest() {
provider = "skalicloud-sdg-my"; provider = "skalicloud-sdg-my";
tag = "skalicloud";
} }
} }

View File

@ -19,11 +19,14 @@
package org.jclouds.slicehost.compute.config; package org.jclouds.slicehost.compute.config;
import static org.jclouds.compute.domain.OsFamily.UBUNTU;
import java.util.Set; import java.util.Set;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.compute.config.BaseComputeServiceContextModule; import org.jclouds.compute.config.BaseComputeServiceContextModule;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.internal.BaseComputeService; import org.jclouds.compute.internal.BaseComputeService;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope; import org.jclouds.domain.LocationScope;
@ -31,6 +34,7 @@ import org.jclouds.domain.internal.LocationImpl;
import org.jclouds.location.Provider; import org.jclouds.location.Provider;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.inject.Injector;
import com.google.inject.Provides; import com.google.inject.Provides;
/** /**
@ -39,6 +43,10 @@ import com.google.inject.Provides;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class SlicehostComputeServiceContextModule extends BaseComputeServiceContextModule { public class SlicehostComputeServiceContextModule extends BaseComputeServiceContextModule {
@Override
protected TemplateBuilder provideTemplate(Injector injector, TemplateBuilder template) {
return template.osFamily(UBUNTU).osVersionMatches("10.04").osDescriptionMatches("^((?!MGC).)*$").os64Bit(true);
}
@Provides @Provides
@Singleton @Singleton

View File

@ -64,7 +64,6 @@ public class TerremarkVCloudExpressTemplateBuilderLiveTest extends BaseTemplateB
assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true); assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true);
assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU); assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU);
assertEquals(getCores(defaultTemplate.getHardware()), 1.0d); assertEquals(getCores(defaultTemplate.getHardware()), 1.0d);
} }
} }

View File

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2010 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.
====================================================================
-->
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<!--
For more configuration infromation and examples see the Apache
Log4j website: http://logging.apache.org/log4j/
-->
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
debug="false">
<!-- A time/date based rolling appender -->
<appender name="WIREFILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds-wire.log" />
<param name="Append" value="true" />
<!-- Rollover at midnight each day -->
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category]
(Thread:NDC) Message\n <param name="ConversionPattern"
value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
-->
</layout>
</appender>
<!-- A time/date based rolling appender -->
<appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds.log" />
<param name="Append" value="true" />
<!-- Rollover at midnight each day -->
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category]
(Thread:NDC) Message\n <param name="ConversionPattern"
value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
-->
</layout>
</appender>
<!-- A time/date based rolling appender -->
<appender name="COMPUTEFILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds-compute.log" />
<param name="Append" value="true" />
<!-- Rollover at midnight each day -->
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category]
(Thread:NDC) Message\n <param name="ConversionPattern"
value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
-->
</layout>
</appender>
<!-- A time/date based rolling appender -->
<appender name="SSHFILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds-ssh.log" />
<param name="Append" value="true" />
<!-- Rollover at midnight each day -->
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category]
(Thread:NDC) Message\n <param name="ConversionPattern"
value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
-->
</layout>
</appender>
<appender name="ASYNCCOMPUTE" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="COMPUTEFILE" />
</appender>
<appender name="ASYNCSSH" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="SSHFILE" />
</appender>
<appender name="ASYNC" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="FILE" />
</appender>
<appender name="ASYNCWIRE" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="WIREFILE" />
</appender>
<!-- ================ -->
<!-- Limit categories -->
<!-- ================ -->
<category name="org.jclouds">
<priority value="DEBUG" />
<appender-ref ref="ASYNC" />
</category>
<category name="jclouds.headers">
<priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" />
</category>
<category name="jclouds.ssh">
<priority value="DEBUG" />
<appender-ref ref="ASYNCSSH" />
</category>
<category name="jclouds.wire">
<priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" />
</category>
<category name="jclouds.compute">
<priority value="TRACE" />
<appender-ref ref="ASYNCCOMPUTE" />
</category>
<!-- ======================= -->
<!-- Setup the Root category -->
<!-- ======================= -->
<root>
<priority value="WARN" />
</root>
</log4j:configuration>