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

View File

@ -22,8 +22,8 @@ package org.jclouds.ec2.compute;
import static com.google.common.base.Preconditions.checkState;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Map.Entry;
import java.util.concurrent.ExecutorService;
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.ResumeNodeStrategy;
import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy;
import org.jclouds.compute.strategy.RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import org.jclouds.compute.strategy.SuspendNodeStrategy;
import org.jclouds.compute.util.ComputeUtils;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.ec2.EC2Client;
@ -81,23 +81,24 @@ public class EC2ComputeService extends BaseComputeService {
@Inject
protected EC2ComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore,
@Memoized Supplier<Set<? extends Image>> images, @Memoized Supplier<Set<? extends Hardware>> sizes,
@Memoized Supplier<Set<? extends Location>> locations, ListNodesStrategy listNodesStrategy,
GetNodeMetadataStrategy getNodeMetadataStrategy, RunNodesAndAddToSetStrategy runNodesAndAddToSetStrategy,
RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy,
ResumeNodeStrategy startNodeStrategy, SuspendNodeStrategy stopNodeStrategy,
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider,
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning,
@Named("NODE_TERMINATED") Predicate<NodeMetadata> nodeTerminated,
@Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended, ComputeUtils utils, Timeouts timeouts,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, EC2Client ec2Client,
Map<RegionAndName, KeyPair> credentialsMap, @Named("SECURITY") Map<RegionAndName, String> securityGroupMap,
@Named("PLACEMENT") Map<RegionAndName, String> placementGroupMap,
@Named("DELETED") Predicate<PlacementGroup> placementGroupDeleted) {
@Memoized Supplier<Set<? extends Image>> images, @Memoized Supplier<Set<? extends Hardware>> sizes,
@Memoized Supplier<Set<? extends Location>> locations, ListNodesStrategy listNodesStrategy,
GetNodeMetadataStrategy getNodeMetadataStrategy, RunNodesAndAddToSetStrategy runNodesAndAddToSetStrategy,
RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy,
ResumeNodeStrategy startNodeStrategy, SuspendNodeStrategy stopNodeStrategy,
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider,
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning,
@Named("NODE_TERMINATED") Predicate<NodeMetadata> nodeTerminated,
@Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended,
RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory statementRunner, Timeouts timeouts,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, EC2Client ec2Client,
Map<RegionAndName, KeyPair> credentialsMap, @Named("SECURITY") Map<RegionAndName, String> securityGroupMap,
@Named("PLACEMENT") Map<RegionAndName, String> placementGroupMap,
@Named("DELETED") Predicate<PlacementGroup> placementGroupDeleted) {
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, stopNodeStrategy,
templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, nodeSuspended, utils,
timeouts, executor);
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy,
stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
nodeSuspended, statementRunner, timeouts, executor);
this.ec2Client = ec2Client;
this.credentialsMap = credentialsMap;
this.securityGroupMap = securityGroupMap;
@ -115,7 +116,7 @@ public class EC2ComputeService extends BaseComputeService {
try {
ec2Client.getPlacementGroupServices().deletePlacementGroupInRegion(region, group);
checkState(placementGroupDeleted.apply(new PlacementGroup(region, group, "cluster", State.PENDING)),
String.format("placementGroup region(%s) name(%s) failed to delete", region, group));
String.format("placementGroup region(%s) name(%s) failed to delete", region, group));
placementGroupMap.remove(new RegionAndName(region, group));
logger.debug("<< deleted placementGroup(%s)", group);
} catch (AWSResponseException e) {
@ -129,8 +130,8 @@ public class EC2ComputeService extends BaseComputeService {
} catch (UnsupportedOperationException e) {
} catch (HttpResponseException e) {
// Eucalyptus does not support placement groups yet.
if (!(e.getResponse().getStatusCode() == 400 && context.getProviderSpecificContext().getProvider()
.equals("eucalyptus")))
if (!(e.getResponse().getStatusCode() == 400 && context.getProviderSpecificContext().getProvider().equals(
"eucalyptus")))
throw e;
}
}

View File

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

View File

@ -29,8 +29,6 @@ import java.util.concurrent.ExecutorService;
import javax.inject.Provider;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.services.PlacementGroupClient;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
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.ResumeNodeStrategy;
import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy;
import org.jclouds.compute.strategy.RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
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 com.google.common.base.Predicate;
@ -52,25 +52,26 @@ import com.google.common.base.Supplier;
@Test(groups = "unit")
public class EC2ComputeServiceTest {
@SuppressWarnings({ "unchecked" })
@SuppressWarnings( { "unchecked" })
public void testUnsupportedOperationOkForPlacementGroups() {
EC2Client client = createMock(EC2Client.class);
EC2ComputeService service = new EC2ComputeService(createMock(ComputeServiceContext.class), createMock(Map.class),
createMock(Supplier.class), createMock(Supplier.class), createMock(Supplier.class),
createMock(ListNodesStrategy.class), createMock(GetNodeMetadataStrategy.class),
createMock(RunNodesAndAddToSetStrategy.class), createMock(RebootNodeStrategy.class),
createMock(DestroyNodeStrategy.class), createMock(ResumeNodeStrategy.class),
createMock(SuspendNodeStrategy.class), createMock(Provider.class), createMock(Provider.class),
createMock(Predicate.class), createMock(Predicate.class), createMock(Predicate.class),
createMock(ComputeUtils.class), createMock(Timeouts.class), createMock(ExecutorService.class), client,
createMock(Map.class), createMock(Map.class), createMock(Map.class), createMock(Predicate.class));
createMock(Supplier.class), createMock(Supplier.class), createMock(Supplier.class),
createMock(ListNodesStrategy.class), createMock(GetNodeMetadataStrategy.class),
createMock(RunNodesAndAddToSetStrategy.class), createMock(RebootNodeStrategy.class),
createMock(DestroyNodeStrategy.class), createMock(ResumeNodeStrategy.class),
createMock(SuspendNodeStrategy.class), createMock(Provider.class), createMock(Provider.class),
createMock(Predicate.class), createMock(Predicate.class), createMock(Predicate.class),
createMock(RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory.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);
// setup expectations
expect(client.getPlacementGroupServices()).andReturn(placementClient).atLeastOnce();
expect(placementClient.describePlacementGroupsInRegion("us-west-1", "jclouds#tag#us-west-1")).andThrow(
new UnsupportedOperationException());
new UnsupportedOperationException());
// replay mocks
replay(client);

View File

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

View File

@ -31,6 +31,7 @@ import java.util.Set;
import org.easymock.IArgumentMatcher;
import org.jclouds.aws.domain.Region;
import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
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.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
/**
* @author Adrian Cole
@ -102,21 +104,20 @@ public class EC2RunNodesAndAddToSetStrategyTest {
InstanceClient instanceClient = createMock(InstanceClient.class);
RunInstancesOptions ec2Options = createMock(RunInstancesOptions.class);
RunningInstance instance = createMock(RunningInstance.class);
Reservation<? extends RunningInstance> reservation = new Reservation<RunningInstance>(region,
ImmutableSet.<String> of(), ImmutableSet.<RunningInstance> of(instance), "ownerId", "requesterId",
"reservationId");
Reservation<? extends RunningInstance> reservation = new Reservation<RunningInstance>(region, ImmutableSet
.<String> of(), ImmutableSet.<RunningInstance> of(instance), "ownerId", "requesterId", "reservationId");
NodeMetadata nodeMetadata = createMock(NodeMetadata.class);
// setup expectations
expect(strategy.client.getInstanceServices()).andReturn(instanceClient).atLeastOnce();
expect(
strategy.createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.execute(region, input.tag,
input.template)).andReturn(ec2Options);
strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize.execute(region, input.tag,
input.template)).andReturn(ec2Options);
expect(input.template.getLocation()).andReturn(input.location).atLeastOnce();
expect(input.template.getImage()).andReturn(input.image).atLeastOnce();
expect(input.image.getProviderId()).andReturn(imageId).atLeastOnce();
expect(instanceClient.runInstancesInRegion(region, zone, imageId, 1, input.count, ec2Options)).andReturn(
(Reservation) reservation);
(Reservation) reservation);
expect(instance.getId()).andReturn(instanceCreatedId).atLeastOnce();
// simulate a lazy credentials fetch
Credentials creds = new Credentials("foo", "bar");
@ -130,8 +131,9 @@ public class EC2RunNodesAndAddToSetStrategyTest {
expect(strategy.runningInstanceToNodeMetadata.apply(instance)).andReturn(nodeMetadata);
expect(
strategy.utils.runOptionsOnNodesAndAddToGoodSetOrPutExceptionIntoBadMap(eq(input.options),
containsNodeMetadata(nodeMetadata), eq(input.nodes), eq(input.badNodes))).andReturn(null);
strategy.utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(eq(input.options),
containsNodeMetadata(nodeMetadata), eq(input.nodes), eq(input.badNodes),
eq(input.customization))).andReturn(null);
// replay mocks
replay(instanceClient);
@ -142,7 +144,7 @@ public class EC2RunNodesAndAddToSetStrategyTest {
replayStrategy(strategy);
// 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(instanceClient);
@ -154,9 +156,9 @@ public class EC2RunNodesAndAddToSetStrategyTest {
}
private static final Location REGION_AP_SOUTHEAST_1 = new LocationImpl(LocationScope.REGION, Region.AP_SOUTHEAST_1,
Region.AP_SOUTHEAST_1, new LocationImpl(LocationScope.PROVIDER, "ec2", "ec2", null));
Region.AP_SOUTHEAST_1, new LocationImpl(LocationScope.PROVIDER, "ec2", "ec2", null));
private static final Location ZONE_AP_SOUTHEAST_1A = new LocationImpl(LocationScope.ZONE,
AvailabilityZone.AP_SOUTHEAST_1A, AvailabilityZone.AP_SOUTHEAST_1A, REGION_AP_SOUTHEAST_1);
AvailabilityZone.AP_SOUTHEAST_1A, AvailabilityZone.AP_SOUTHEAST_1A, REGION_AP_SOUTHEAST_1);
// /////////////////////////////////////////////////////////////////////
@SuppressWarnings("unchecked")
@ -166,6 +168,7 @@ public class EC2RunNodesAndAddToSetStrategyTest {
Template template = createMock(Template.class);
Set<NodeMetadata> nodes = createMock(Set.class);
Map<NodeMetadata, Exception> badNodes = createMock(Map.class);
Multimap<NodeMetadata, CustomizationResponse> customization = createMock(Multimap.class);
Hardware hardware = createMock(Hardware.class);
Image image = createMock(Image.class);
final Location location;
@ -181,6 +184,7 @@ public class EC2RunNodesAndAddToSetStrategyTest {
replay(image);
replay(nodes);
replay(badNodes);
replay(customization);
replay(options);
}
@ -190,12 +194,13 @@ public class EC2RunNodesAndAddToSetStrategyTest {
verify(image);
verify(nodes);
verify(badNodes);
verify(customization);
verify(options);
}
}
private void verifyStrategy(EC2RunNodesAndAddToSetStrategy strategy) {
verify(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions);
verify(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize);
verify(strategy.client);
verify(strategy.instancePresent);
verify(strategy.runningInstanceToNodeMetadata);
@ -207,18 +212,18 @@ public class EC2RunNodesAndAddToSetStrategyTest {
@SuppressWarnings("unchecked")
private EC2RunNodesAndAddToSetStrategy setupStrategy() {
EC2Client client = createMock(EC2Client.class);
CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions = createMock(CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions.class);
CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = createMock(CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions.class);
Predicate<RunningInstance> instanceStateRunning = createMock(Predicate.class);
RunningInstanceToNodeMetadata runningInstanceToNodeMetadata = createMock(RunningInstanceToNodeMetadata.class);
Function<RunningInstance, Credentials> instanceToCredentials = createMock(Function.class);
Map<String, Credentials> credentialStore = createMock(Map.class);
ComputeUtils utils = createMock(ComputeUtils.class);
return new EC2RunNodesAndAddToSetStrategy(client, createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions,
instanceStateRunning, runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils);
return new EC2RunNodesAndAddToSetStrategy(client, createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
instanceStateRunning, runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils);
}
private void replayStrategy(EC2RunNodesAndAddToSetStrategy strategy) {
replay(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions);
replay(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize);
replay(strategy.client);
replay(strategy.instancePresent);
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.ResumeNodeStrategy;
import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy;
import org.jclouds.compute.strategy.RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import org.jclouds.compute.strategy.SuspendNodeStrategy;
import org.jclouds.compute.util.ComputeUtils;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.vcloud.terremark.compute.domain.KeyPairCredentials;
@ -75,13 +75,14 @@ public class TerremarkVCloudComputeService extends BaseComputeService {
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider,
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning,
@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,
ConcurrentMap<OrgAndName, KeyPairCredentials> credentialsMap, NodeMetadataToOrgAndName nodeToOrgAndName) {
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, resumeNodeStrategy,
suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
nodeSuspended, utils, timeouts, executor);
nodeSuspended, statementRunner, timeouts, executor);
this.cleanupOrphanKeys = cleanupOrphanKeys;
}

View File

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

View File

@ -30,15 +30,18 @@ import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.strategy.AddNodeWithTagStrategy;
import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import org.jclouds.compute.strategy.ListNodesStrategy;
import org.jclouds.compute.strategy.impl.EncodeTagIntoNameRunNodesAndAddToSetStrategy;
import org.jclouds.compute.util.ComputeUtils;
import org.jclouds.domain.LocationScope;
import org.jclouds.vcloud.terremark.compute.options.TerremarkVCloudTemplateOptions;
import com.google.common.collect.Multimap;
/**
* creates futures that correlate to
*
@ -50,23 +53,27 @@ public class TerremarkEncodeTagIntoNameRunNodesAndAddToSetStrategy extends Encod
private final CreateNewKeyPairUnlessUserSpecifiedOtherwise createNewKeyPairUnlessUserSpecifiedOtherwise;
@Inject
protected TerremarkEncodeTagIntoNameRunNodesAndAddToSetStrategy(AddNodeWithTagStrategy addNodeWithTagStrategy,
ListNodesStrategy listNodesStrategy, @Named("NAMING_CONVENTION") String nodeNamingConvention,
ComputeUtils utils, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor,
protected TerremarkEncodeTagIntoNameRunNodesAndAddToSetStrategy(
AddNodeWithTagStrategy addNodeWithTagStrategy,
ListNodesStrategy listNodesStrategy,
@Named("NAMING_CONVENTION") String nodeNamingConvention,
CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor,
CreateNewKeyPairUnlessUserSpecifiedOtherwise createNewKeyPairUnlessUserSpecifiedOtherwise) {
super(addNodeWithTagStrategy, listNodesStrategy, nodeNamingConvention, utils, executor);
super(addNodeWithTagStrategy, listNodesStrategy, nodeNamingConvention, executor,
customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory);
this.createNewKeyPairUnlessUserSpecifiedOtherwise = createNewKeyPairUnlessUserSpecifiedOtherwise;
}
@Override
public Map<?, Future<Void>> execute(String tag, int count, Template template, Set<NodeMetadata> nodes,
Map<NodeMetadata, Exception> badNodes) {
public Map<?, Future<Void>> execute(String tag, int count, Template template, Set<NodeMetadata> goodNodes,
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: "
+ template.getLocation();
String orgId = template.getLocation().getParent().getId();
assert orgId.startsWith("http") : "parent id should be a rest url: " + template.getLocation().getParent();
createNewKeyPairUnlessUserSpecifiedOtherwise.execute(URI.create(orgId), tag, template.getImage()
.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 org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
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.domain.Location;
import org.jclouds.io.Payload;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.ssh.ExecResponse;
import com.google.common.base.Predicate;
@ -137,7 +138,7 @@ public interface ComputeService {
* default, equivalent to {@code templateBuilder().any().options(templateOptions)}.
*/
Set<? extends NodeMetadata> runNodesWithTag(String tag, int count, TemplateOptions templateOptions)
throws RunNodesException;
throws RunNodesException;
/**
* Like {@link ComputeService#runNodesWithTag(String,int,TemplateOptions)}, except that the
@ -238,11 +239,12 @@ public interface ComputeService {
* org.jclouds.compute.options.RunScriptOptions)
* @see org.jclouds.compute.predicates.NodePredicates#runningWithTag(String)
*/
@Deprecated
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
* 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.io.Payloads
*/
@Deprecated
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.options.RunScriptOptions;
import org.jclouds.io.Payload;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.ssh.ExecResponse;
/**
@ -39,17 +39,17 @@ public class RunScriptOnNodesException extends Exception {
/** The serialVersionUID */
private static final long serialVersionUID = -2272965726680821281L;
private final Payload runScript;
private final Statement runScript;
private final RunScriptOptions options;
private final Map<NodeMetadata, ExecResponse> successfulNodes;
private final Map<? extends NodeMetadata, ? extends Throwable> failedNodes;
private final Map<?, Exception> executionExceptions;
public RunScriptOnNodesException(final Payload runScript, @Nullable final RunScriptOptions options,
Map<NodeMetadata, ExecResponse> successfulNodes, Map<?, Exception> executionExceptions,
Map<? extends NodeMetadata, ? extends Throwable> failedNodes) {
public RunScriptOnNodesException(Statement runScript, @Nullable RunScriptOptions options,
Map<NodeMetadata, ExecResponse> successfulNodes, Map<?, Exception> executionExceptions,
Map<? extends NodeMetadata, ? extends Throwable> failedNodes) {
super(String.format("error runScript on filtered nodes options(%s)%n%s%n%s", options,
createExecutionErrorMessage(executionExceptions), createNodeErrorMessage(failedNodes)));
createExecutionErrorMessage(executionExceptions), createNodeErrorMessage(failedNodes)));
this.runScript = runScript;
this.options = options;
this.successfulNodes = successfulNodes;
@ -66,8 +66,7 @@ public class RunScriptOnNodesException extends Exception {
/**
*
* @return Nodes that performed startup without error, but incurred problems
* applying options
* @return Nodes that performed startup without error, but incurred problems applying options
*/
public Map<?, ? extends Throwable> getExecutionErrors() {
return executionExceptions;
@ -75,14 +74,13 @@ public class RunScriptOnNodesException extends Exception {
/**
*
* @return Nodes that performed startup without error, but incurred problems
* applying options
* @return Nodes that performed startup without error, but incurred problems applying options
*/
public Map<? extends NodeMetadata, ? extends Throwable> getNodeErrors() {
return failedNodes;
}
public Payload getRunScript() {
public Statement getRunScript() {
return runScript;
}

View File

@ -22,9 +22,15 @@ package org.jclouds.compute.callables;
import static com.google.common.base.Preconditions.checkNotNull;
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.util.ComputeServiceUtils.SshCallable;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger;
import org.jclouds.scriptbuilder.InitBuilder;
import org.jclouds.scriptbuilder.domain.OsFamily;
@ -33,23 +39,51 @@ import org.jclouds.ssh.ExecResponse;
import org.jclouds.ssh.SshClient;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.inject.assistedinject.Assisted;
/**
*
* @author Adrian Cole
*/
public class InitAndStartScriptOnNode implements SshCallable<ExecResponse> {
protected SshClient ssh;
protected final NodeMetadata node;
protected final InitBuilder init;
protected final boolean runAsRoot;
public class StartInitScriptOnNode implements Callable<ExecResponse> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
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");
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)
: createInitScript(checkNotNull(name, "name"), script);
this.name = checkNotNull(name, "name");
this.runAsRoot = runAsRoot;
}
@ -60,13 +94,28 @@ public class InitAndStartScriptOnNode implements SshCallable<ExecResponse> {
@Override
public ExecResponse call() {
ssh.put(init.getInstanceName(), init.render(OsFamily.UNIX));
ssh.exec("chmod 755 " + init.getInstanceName());
ssh = sshFactory.apply(node);
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");
return runAction("start");
}
private ExecResponse runAction(String action) {
protected ExecResponse runAction(String action) {
ExecResponse returnVal;
String command = (runAsRoot) ? execScriptAsRoot(action) : execScriptAsDefaultUser(action);
returnVal = runCommand(command);
@ -84,30 +133,23 @@ public class InitAndStartScriptOnNode implements SshCallable<ExecResponse> {
return returnVal;
}
@Override
public void setConnection(SshClient ssh, Logger logger) {
this.logger = checkNotNull(logger, "logger");
this.ssh = checkNotNull(ssh, "ssh");
}
@VisibleForTesting
public String execScriptAsRoot(String action) {
String command;
if (node.getCredentials().identity.equals("root")) {
command = "./" + init.getInstanceName() + " " + action;
command = "./" + name + " " + action;
} 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 {
command = "sudo ./" + init.getInstanceName() + " " + action;
command = "sudo ./" + name + " " + action;
}
return command;
}
protected String execScriptAsDefaultUser(String action) {
return "./" + init.getInstanceName() + " " + action;
return "./" + name + " " + action;
}
@Override
public NodeMetadata getNode() {
return node;
}

View File

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

View File

@ -24,12 +24,15 @@ import static org.jclouds.compute.domain.OsFamily.UBUNTU;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Named;
import javax.inject.Singleton;
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.Hardware;
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.TemplateBuilder;
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.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import org.jclouds.compute.strategy.RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import org.jclouds.compute.util.ComputeServiceUtils;
import org.jclouds.domain.Location;
import org.jclouds.json.Json;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.suppliers.RetryOnTimeOutButNotOnAuthorizationExceptionSupplier;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.ssh.SshClient;
import com.google.common.base.Function;
@ -52,6 +61,8 @@ import com.google.inject.AbstractModule;
import com.google.inject.Injector;
import com.google.inject.Provides;
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());
bind(new TypeLiteral<Function<NodeMetadata, SshClient>>() {
}).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
@ -118,20 +146,20 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule {
@Singleton
@Memoized
protected Supplier<Set<? extends Image>> supplyImageCache(@Named(PROPERTY_SESSION_INTERVAL) long seconds,
final Supplier<Set<? extends Image>> imageSupplier) {
final Supplier<Set<? extends Image>> imageSupplier) {
return new RetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Set<? extends Image>>(authException, seconds,
new Supplier<Set<? extends Image>>() {
@Override
public Set<? extends Image> get() {
return imageSupplier.get();
}
});
new Supplier<Set<? extends Image>>() {
@Override
public Set<? extends Image> get() {
return imageSupplier.get();
}
});
}
@Provides
@Singleton
protected Supplier<Map<String, ? extends Location>> provideLocationMap(
@Memoized Supplier<Set<? extends Location>> locations) {
@Memoized Supplier<Set<? extends Location>> locations) {
return Suppliers.compose(new Function<Set<? extends Location>, Map<String, ? extends Location>>() {
@Override
@ -153,14 +181,14 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule {
@Singleton
@Memoized
protected Supplier<Set<? extends Location>> supplyLocationCache(@Named(PROPERTY_SESSION_INTERVAL) long seconds,
final Supplier<Set<? extends Location>> locationSupplier) {
final Supplier<Set<? extends Location>> locationSupplier) {
return new RetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Set<? extends Location>>(authException, seconds,
new Supplier<Set<? extends Location>>() {
@Override
public Set<? extends Location> get() {
return locationSupplier.get();
}
});
new Supplier<Set<? extends Location>>() {
@Override
public Set<? extends Location> get() {
return locationSupplier.get();
}
});
}
@Provides
@ -187,14 +215,14 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule {
@Singleton
@Memoized
protected Supplier<Set<? extends Hardware>> supplySizeCache(@Named(PROPERTY_SESSION_INTERVAL) long seconds,
final Supplier<Set<? extends Hardware>> hardwareSupplier) {
final Supplier<Set<? extends Hardware>> hardwareSupplier) {
return new RetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Set<? extends Hardware>>(authException, seconds,
new Supplier<Set<? extends Hardware>>() {
@Override
public Set<? extends Hardware> get() {
return hardwareSupplier.get();
}
});
new Supplier<Set<? extends Hardware>>() {
@Override
public Set<? extends Hardware> get() {
return hardwareSupplier.get();
}
});
}
@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() {
bind(new TypeLiteral<ComputeServiceAdapter<NodeMetadata, Hardware, Image, Location>>() {
}).to(adapter);
bind(IdentityFunction.class).toInstance(IdentityFunction.INSTANCE);
bind(new TypeLiteral<Function<NodeMetadata, NodeMetadata>>() {
}).to((Class) IdentityFunction.class);
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.filter;
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.Sets.filter;
import static com.google.common.collect.Sets.newHashSet;
import static com.google.common.collect.Sets.newLinkedHashSet;
import static com.google.common.util.concurrent.Futures.immediateFuture;
import static org.jclouds.compute.predicates.NodePredicates.TERMINATED;
@ -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.transformParallel;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
@ -59,6 +58,7 @@ import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.RunScriptOnNodesException;
import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.Hardware;
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.ResumeNodeStrategy;
import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy;
import org.jclouds.compute.strategy.RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import org.jclouds.compute.strategy.SuspendNodeStrategy;
import org.jclouds.compute.util.ComputeUtils;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.io.Payload;
import org.jclouds.logging.Logger;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.ssh.ExecResponse;
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.Predicate;
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 Map<String, Credentials> credentialStore;
protected final Supplier<Set<? extends Image>> images;
protected final Supplier<Set<? extends Hardware>> hardwareProfiles;
protected final Supplier<Set<? extends Location>> locations;
protected final ListNodesStrategy listNodesStrategy;
protected final GetNodeMetadataStrategy getNodeMetadataStrategy;
protected final RunNodesAndAddToSetStrategy runNodesAndAddToSetStrategy;
protected final RebootNodeStrategy rebootNodeStrategy;
protected final DestroyNodeStrategy destroyNodeStrategy;
protected final ResumeNodeStrategy resumeNodeStrategy;
protected final SuspendNodeStrategy suspendNodeStrategy;
protected final Provider<TemplateBuilder> templateBuilderProvider;
protected final Provider<TemplateOptions> templateOptionsProvider;
protected final Predicate<NodeMetadata> nodeRunning;
protected final Predicate<NodeMetadata> nodeTerminated;
protected final Predicate<NodeMetadata> nodeSuspended;
protected final ComputeUtils utils;
protected final Timeouts timeouts;
protected final ExecutorService executor;
private final Supplier<Set<? extends Image>> images;
private final Supplier<Set<? extends Hardware>> hardwareProfiles;
private final Supplier<Set<? extends Location>> locations;
private final ListNodesStrategy listNodesStrategy;
private final GetNodeMetadataStrategy getNodeMetadataStrategy;
private final RunNodesAndAddToSetStrategy runNodesAndAddToSetStrategy;
private final RebootNodeStrategy rebootNodeStrategy;
private final DestroyNodeStrategy destroyNodeStrategy;
private final ResumeNodeStrategy resumeNodeStrategy;
private final SuspendNodeStrategy suspendNodeStrategy;
private final Provider<TemplateBuilder> templateBuilderProvider;
private final Provider<TemplateOptions> templateOptionsProvider;
private final Predicate<NodeMetadata> nodeRunning;
private final Predicate<NodeMetadata> nodeTerminated;
private final Predicate<NodeMetadata> nodeSuspended;
private final RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory statementRunner;
private final Timeouts timeouts;
private final ExecutorService executor;
@Inject
protected BaseComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore,
@ -134,7 +139,8 @@ public class BaseComputeService implements ComputeService {
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider,
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning,
@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) {
this.context = checkNotNull(context, "context");
this.credentialStore = checkNotNull(credentialStore, "credentialStore");
@ -153,7 +159,7 @@ public class BaseComputeService implements ComputeService {
this.nodeRunning = checkNotNull(nodeRunning, "nodeRunning");
this.nodeTerminated = checkNotNull(nodeTerminated, "nodeTerminated");
this.nodeSuspended = checkNotNull(nodeSuspended, "nodeSuspended");
this.utils = checkNotNull(utils, "utils");
this.statementRunner = checkNotNull(statementRunner, "statementRunner");
this.timeouts = checkNotNull(timeouts, "timeouts");
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,
count > 1 ? "s" : "", tag, template.getLocation().getId(), template.getImage().getId(), template
.getHardware().getId(), template.getOptions());
Set<NodeMetadata> nodes = newHashSet();
Set<NodeMetadata> goodNodes = newLinkedHashSet();
Map<NodeMetadata, Exception> badNodes = newLinkedHashMap();
Map<?, Future<Void>> responses = runNodesAndAddToSetStrategy.execute(tag, count, template, nodes, badNodes);
Map<?, Exception> executionExceptions = awaitCompletion(responses, executor, null, logger, "resumeing nodes");
for (NodeMetadata node : concat(nodes, badNodes.keySet()))
Multimap<NodeMetadata, CustomizationResponse> customizationResponses = LinkedHashMultimap.create();
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)
credentialStore.put("node#" + node.getId(), node.getCredentials());
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}
*/
@Override
public Map<NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter,
final Payload runScript, @Nullable final RunScriptOptions options) throws RunScriptOnNodesException {
public Map<NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter, Payload runScript,
@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(runScript, "runScript");
checkNotNull(options, "options");
if (options.getTaskName() == null)
options.nameTask("jclouds-script-" + System.currentTimeMillis());
Iterable<? extends NodeMetadata> nodes = filter(detailsOnAllNodes(), filter);
final Map<NodeMetadata, ExecResponse> execs = newHashMap();
final Map<NodeMetadata, Future<Void>> responses = newHashMap();
final Map<NodeMetadata, Exception> badNodes = newLinkedHashMap();
Map<NodeMetadata, ExecResponse> goodNodes = newLinkedHashMap();
Map<NodeMetadata, Exception> badNodes = newLinkedHashMap();
Map<NodeMetadata, Future<Void>> responses = newLinkedHashMap();
nodes = filterNodesWhoCanRunScripts(nodes, badNodes, options.getOverrideCredentials());
for (final NodeMetadata node : nodes) {
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;
}
}));
for (NodeMetadata node : nodes) {
responses.put(node, executor.submit(statementRunner.create(node, runScript, options, goodNodes, badNodes)));
}
Map<?, Exception> exceptions = awaitCompletion(responses, executor, null, logger, "running script on nodes");
if (exceptions.size() > 0 || badNodes.size() > 0) {
throw new RunScriptOnNodesException(runScript, options, execs, exceptions, badNodes);
throw new RunScriptOnNodesException(runScript, options, goodNodes, exceptions, badNodes);
}
return execs;
return goodNodes;
}

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.Set;
import java.util.concurrent.Future;
import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.strategy.impl.EncodeTagIntoNameRunNodesAndAddToSetStrategy;
import java.util.concurrent.Future;
import com.google.common.collect.Multimap;
import com.google.inject.ImplementedBy;
/**
@ -37,6 +39,6 @@ import com.google.inject.ImplementedBy;
@ImplementedBy(EncodeTagIntoNameRunNodesAndAddToSetStrategy.class)
public interface RunNodesAndAddToSetStrategy {
Map<?, Future<Void>> execute(String tag, int count, Template template,
Set<NodeMetadata> nodes, Map<NodeMetadata, Exception> badNodes);
Map<?, Future<Void>> execute(String tag, int count, Template template, Set<NodeMetadata> goodNodes,
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;
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.util.Map;
import java.util.Set;
@ -32,20 +39,19 @@ import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.strategy.AddNodeWithTagStrategy;
import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import org.jclouds.compute.strategy.ListNodesStrategy;
import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy;
import org.jclouds.compute.util.ComputeUtils;
import org.jclouds.logging.Logger;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.collect.Multimap;
/**
* creates futures that correlate to
@ -54,24 +60,54 @@ import com.google.common.collect.Sets;
*/
@Singleton
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
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
protected final AddNodeWithTagStrategy addNodeWithTagStrategy;
protected final ListNodesStrategy listNodesStrategy;
protected final String nodeNamingConvention;
protected final ComputeUtils utils;
protected final ExecutorService executor;
protected final CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory;
@Inject
protected EncodeTagIntoNameRunNodesAndAddToSetStrategy(AddNodeWithTagStrategy addNodeWithTagStrategy,
ListNodesStrategy listNodesStrategy, @Named("NAMING_CONVENTION") String nodeNamingConvention,
ComputeUtils utils, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
protected EncodeTagIntoNameRunNodesAndAddToSetStrategy(
AddNodeWithTagStrategy addNodeWithTagStrategy,
ListNodesStrategy listNodesStrategy,
@Named("NAMING_CONVENTION") String nodeNamingConvention,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor,
CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory) {
this.addNodeWithTagStrategy = addNodeWithTagStrategy;
this.listNodesStrategy = listNodesStrategy;
this.nodeNamingConvention = nodeNamingConvention;
this.utils = utils;
this.executor = executor;
this.customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory = customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory;
}
/**
@ -79,22 +115,13 @@ public class EncodeTagIntoNameRunNodesAndAddToSetStrategy implements RunNodesAnd
* simultaneously runs the nodes and applies options to them.
*/
@Override
public Map<?, Future<Void>> execute(final String tag, final int count, final Template template,
final Set<NodeMetadata> nodes, final Map<NodeMetadata, Exception> badNodes) {
Map<String, Future<Void>> responses = Maps.newHashMap();
for (final String name : getNextNames(tag, template, count)) {
responses.put(name, executor.submit(new Callable<Void>() {
@Override
public Void 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());
utils.runOptionsOnNodeAndAddToGoodSetOrPutExceptionIntoBadMap(node, badNodes, nodes,
template.getOptions()).call();
return null;
}
}));
public Map<?, Future<Void>> execute(String tag, int count, Template template, Set<NodeMetadata> goodNodes,
Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
Map<String, Future<Void>> responses = newLinkedHashMap();
for (String name : getNextNames(tag, template, count)) {
responses.put(name, compose(executor.submit(new AddNode(name, tag, template)),
customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory.create(template.getOptions(),
goodNodes, badNodes, customizationResponses), executor));
}
return responses;
}
@ -110,13 +137,13 @@ public class EncodeTagIntoNameRunNodesAndAddToSetStrategy implements RunNodesAnd
* @return
*/
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();
int maxTries = 100;
int currentTries = 0;
while (names.size() < count && currentTries++ < maxTries) {
final String name = getNextName(tag, template);
if (!Iterables.any(currentNodes, new Predicate<ComputeMetadata>() {
if (!any(currentNodes, new Predicate<ComputeMetadata>() {
@Override
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.util.Formatter;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.concurrent.Callable;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Resource;
import javax.inject.Named;
import org.jclouds.compute.ComputeServiceContextBuilder;
import org.jclouds.compute.domain.ComputeMetadata;
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.Volume;
import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.http.HttpRequest;
import org.jclouds.logging.Logger;
import org.jclouds.net.IPSocket;
import org.jclouds.rest.Providers;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.ssh.SshClient;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
@ -84,7 +86,7 @@ public class ComputeServiceUtils {
*/
public static Statement extractTargzIntoDirectory(HttpRequest targz, String directory) {
return Statements
.extractTargzIntoDirectory(targz.getMethod(), targz.getEndpoint(), targz.getHeaders(), directory);
.extractTargzIntoDirectory(targz.getMethod(), targz.getEndpoint(), targz.getHeaders(), directory);
}
public static Statement extractTargzIntoDirectory(URI targz, String directory) {
@ -104,9 +106,23 @@ public class ComputeServiceUtils {
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) {
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) {
@ -147,8 +163,8 @@ public class ComputeServiceUtils {
Formatter fmt = new Formatter().format("Execution failures:%n%n");
int index = 1;
for (Entry<?, Exception> errorMessage : executionExceptions.entrySet()) {
fmt.format("%s) %s on %s:%n%s%n%n", index++, errorMessage.getValue().getClass().getSimpleName(),
errorMessage.getKey(), getStackTraceAsString(errorMessage.getValue()));
fmt.format("%s) %s on %s:%n%s%n%n", index++, errorMessage.getValue().getClass().getSimpleName(), errorMessage
.getKey(), getStackTraceAsString(errorMessage.getValue()));
}
return fmt.format("%s error[s]", executionExceptions.size()).toString();
}
@ -158,13 +174,13 @@ public class ComputeServiceUtils {
int index = 1;
for (Entry<? extends NodeMetadata, ? extends Throwable> errorMessage : failedNodes.entrySet()) {
fmt.format("%s) %s on node %s:%n%s%n%n", index++, errorMessage.getValue().getClass().getSimpleName(),
errorMessage.getKey().getId(), getStackTraceAsString(errorMessage.getValue()));
errorMessage.getKey().getId(), getStackTraceAsString(errorMessage.getValue()));
}
return fmt.format("%s error[s]", failedNodes.size()).toString();
}
public static Iterable<? extends ComputeMetadata> filterByName(Iterable<? extends ComputeMetadata> nodes,
final String name) {
final String name) {
return filter(nodes, new Predicate<ComputeMetadata>() {
@Override
public boolean apply(ComputeMetadata input) {
@ -173,30 +189,23 @@ public class ComputeServiceUtils {
});
}
public static interface SshCallable<T> extends Callable<T> {
NodeMetadata getNode();
void setConnection(SshClient ssh, Logger logger);
}
public static Iterable<String> getSupportedProviders() {
return Providers.getSupportedProvidersOfType(ComputeServiceContextBuilder.class);
}
public static IPSocket findReachableSocketOnNode(RetryIfSocketNotYetOpen socketTester, final NodeMetadata node,
final int port) {
final int port) {
checkNodeHasIps(node);
IPSocket socket = null;
try {
socket = find(
transform(concat(node.getPublicAddresses(), node.getPrivateAddresses()),
new Function<String, IPSocket>() {
socket = find(transform(concat(node.getPublicAddresses(), node.getPrivateAddresses()),
new Function<String, IPSocket>() {
@Override
public IPSocket apply(String from) {
return new IPSocket(from, port);
}
}), socketTester);
@Override
public IPSocket apply(String from) {
return new IPSocket(from, port);
}
}), socketTester);
} catch (NoSuchElementException e) {
throw new RuntimeException(String.format("could not connect to any ip address port %d on node %s", port, node));
}
@ -205,11 +214,11 @@ public class ComputeServiceUtils {
public static void checkNodeHasIps(NodeMetadata node) {
checkState(size(concat(node.getPublicAddresses(), node.getPrivateAddresses())) > 0,
"node does not have IP addresses configured: " + node);
"node does not have IP addresses configured: " + node);
}
public static String parseVersionOrReturnEmptyString(org.jclouds.compute.domain.OsFamily family, final String in,
Map<OsFamily, Map<String, String>> osVersionMap) {
Map<OsFamily, Map<String, String>> osVersionMap) {
if (osVersionMap.containsKey(family)) {
if (osVersionMap.get(family).containsKey(in))
return osVersionMap.get(family).get(in);

View File

@ -19,53 +19,24 @@
package org.jclouds.compute.util;
import static com.google.common.base.Throwables.getRootCause;
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 static com.google.common.collect.Maps.newLinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import javax.annotation.Nullable;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.compute.callables.InitAndStartScriptOnNode;
import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.config.CustomizationResponse;
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.predicates.RetryIfSocketNotYetOpen;
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 org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.inject.Inject;
import com.google.common.collect.Multimap;
/**
*
@ -73,168 +44,26 @@ import com.google.inject.Inject;
*/
@Singleton
public class ComputeUtils {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
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;
private final CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory;
private final ExecutorService executor;
@Inject
public ComputeUtils(Provider<RetryIfSocketNotYetOpen> socketTester, Function<NodeMetadata, SshClient> sshFactory,
@Named("SCRIPT_COMPLETE") Predicate<CommandUsingClient> runScriptNotRunning, GetNodeMetadataStrategy getNode,
Timeouts timeouts, @Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
this.sshFactory = sshFactory;
this.nodeRunning = nodeRunning;
this.timeouts = timeouts;
this.getNode = getNode;
this.socketTester = socketTester;
this.runScriptNotRunning = runScriptNotRunning;
public ComputeUtils(
CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
this.customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory = customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory;
this.executor = executor;
}
public Map<?, Future<Void>> runOptionsOnNodesAndAddToGoodSetOrPutExceptionIntoBadMap(final TemplateOptions options,
Iterable<NodeMetadata> runningNodes, final Set<NodeMetadata> goodNodes,
final Map<NodeMetadata, Exception> badNodes) {
Map<NodeMetadata, Future<Void>> responses = newHashMap();
for (final NodeMetadata node : runningNodes) {
responses.put(node, executor.submit(runOptionsOnNodeAndAddToGoodSetOrPutExceptionIntoBadMap(node, badNodes,
goodNodes, options)));
public Map<?, Future<Void>> customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(TemplateOptions options,
Iterable<NodeMetadata> runningNodes, Set<NodeMetadata> goodNodes, Map<NodeMetadata, Exception> badNodes,
Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
Map<NodeMetadata, Future<Void>> responses = newLinkedHashMap();
for (NodeMetadata node : runningNodes) {
responses.put(node, executor.submit(customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory.create(
options, node, goodNodes, badNodes, customizationResponses)));
}
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;
import org.jclouds.compute.config.CustomizationResponse;
/**
* @author Adrian Cole
*/
public class ExecResponse {
public class ExecResponse implements CustomizationResponse {
private final String error;
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.withTag;
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.assertNotNull;
@ -75,7 +74,6 @@ import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.predicates.SocketOpen;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.ssh.ExecResponse;
import org.jclouds.ssh.SshClient;
import org.jclouds.ssh.SshException;
@ -159,8 +157,8 @@ public abstract class BaseComputeServiceLiveTest {
if (context != null)
context.close();
Properties props = setupProperties();
context = new ComputeServiceContextFactory(getRestProperties()).createContext(provider,
ImmutableSet.of(new Log4JLoggingModule(), getSshModule()), props);
context = new ComputeServiceContextFactory(getRestProperties()).createContext(provider, ImmutableSet.of(
new Log4JLoggingModule(), getSshModule()), props);
client = context.getComputeService();
}
@ -180,8 +178,8 @@ public abstract class BaseComputeServiceLiveTest {
public void testCorrectAuthException() throws Exception {
ComputeServiceContext context = null;
try {
context = new ComputeServiceContextFactory().createContext(provider, "MOMMA", "MIA",
ImmutableSet.<Module> of(new Log4JLoggingModule()));
context = new ComputeServiceContextFactory().createContext(provider, "MOMMA", "MIA", ImmutableSet
.<Module> of(new Log4JLoggingModule()));
context.getComputeService().listNodes();
} catch (AuthorizationException e) {
throw e;
@ -224,7 +222,7 @@ public abstract class BaseComputeServiceLiveTest {
OperatingSystem os = get(nodes, 0).getOperatingSystem();
try {
Map<? extends NodeMetadata, ExecResponse> responses = runScriptWithCreds(tag, os, new Credentials(
good.identity, "romeo"));
good.identity, "romeo"));
assert false : "shouldn't pass with a bad password\n" + responses;
} catch (RunScriptOnNodesException e) {
assert getRootCause(e).getMessage().contains("Auth fail") : e;
@ -283,7 +281,7 @@ public abstract class BaseComputeServiceLiveTest {
template = buildTemplate(client.templateBuilder());
template.getOptions().installPrivateKey(keyPair.get("private")).authorizePublicKey(keyPair.get("public"))
.runScript(buildScript(template.getImage().getOperatingSystem()));
.runScript(buildScript(template.getImage().getOperatingSystem()));
}
protected void checkImageIdMatchesTemplate(NodeMetadata node) {
@ -294,8 +292,8 @@ public abstract class BaseComputeServiceLiveTest {
protected void checkOsMatchesTemplate(NodeMetadata node) {
if (node.getOperatingSystem() != null)
assert node.getOperatingSystem().getFamily().equals(template.getImage().getOperatingSystem().getFamily()) : String
.format("expecting family %s but got %s", template.getImage().getOperatingSystem().getFamily(),
node.getOperatingSystem());
.format("expecting family %s but got %s", template.getImage().getOperatingSystem().getFamily(), node
.getOperatingSystem());
}
void assertLocationSameOrChild(Location test, Location expected) {
@ -327,11 +325,10 @@ public abstract class BaseComputeServiceLiveTest {
}
protected Map<? extends NodeMetadata, ExecResponse> runScriptWithCreds(final String tag, OperatingSystem os,
Credentials creds) throws RunScriptOnNodesException {
Credentials creds) throws RunScriptOnNodesException {
try {
return client.runScriptOnNodesMatching(runningWithTag(tag),
newStringPayload(buildScript(os).render(OsFamily.UNIX)),
overrideCredentialsWith(creds).nameTask("runScriptWithCreds"));
return client.runScriptOnNodesMatching(runningWithTag(tag), buildScript(os), overrideCredentialsWith(creds)
.nameTask("runScriptWithCreds"));
} catch (SshException e) {
throw e;
}
@ -361,16 +358,16 @@ public abstract class BaseComputeServiceLiveTest {
@Test(enabled = true, dependsOnMethods = "testCreateAnotherNodeWithANewContextToEnsureSharedMemIsntRequired")
public void testGet() throws Exception {
Map<String, ? extends NodeMetadata> metadataMap = newLinkedHashMap(uniqueIndex(
filter(client.listNodesDetailsMatching(all()), and(withTag(tag), not(TERMINATED))),
new Function<NodeMetadata, String>() {
Map<String, ? extends NodeMetadata> metadataMap = newLinkedHashMap(uniqueIndex(filter(client
.listNodesDetailsMatching(all()), and(withTag(tag), not(TERMINATED))),
new Function<NodeMetadata, String>() {
@Override
public String apply(NodeMetadata from) {
return from.getId();
}
@Override
public String apply(NodeMetadata from) {
return from.getId();
}
}));
}));
for (NodeMetadata node : nodes) {
metadataMap.remove(node.getId());
NodeMetadata metadata = client.getNodeMetadata(node.getId());
@ -389,7 +386,7 @@ public abstract class BaseComputeServiceLiveTest {
protected void assertNodeZero(Collection<? extends NodeMetadata> metadataSet) {
assert metadataSet.size() == 0 : String.format("nodes left in set: [%s] which didn't match set: [%s]",
metadataSet, nodes);
metadataSet, nodes);
}
@Test(enabled = true, dependsOnMethods = "testGet")
@ -453,7 +450,9 @@ public abstract class BaseComputeServiceLiveTest {
@Test(enabled = true, dependsOnMethods = { "testListNodes", "testGetNodesWithDetails" })
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))) {
assert node.getState() == NodeState.TERMINATED : node;
assertEquals(context.getCredentialStore().get("node#" + node.getId()), null);
@ -475,12 +474,12 @@ public abstract class BaseComputeServiceLiveTest {
}
template = client.templateBuilder().options(blockOnComplete(false).blockOnPort(8080, 600).inboundPorts(22, 8080))
.build();
.build();
// note this is a dependency on the template resolution
template.getOptions().runScript(
RunScriptData.createScriptInstallAndStartJBoss(keyPair.get("public"), template.getImage()
.getOperatingSystem()));
RunScriptData.createScriptInstallAndStartJBoss(keyPair.get("public"), template.getImage()
.getOperatingSystem()));
try {
NodeMetadata node = getOnlyElement(client.runNodesWithTag(tag, 1, template));
@ -514,26 +513,26 @@ public abstract class BaseComputeServiceLiveTest {
assert location != location.getParent() : location;
assert location.getScope() != null : location;
switch (location.getScope()) {
case PROVIDER:
assertProvider(location);
break;
case REGION:
assertProvider(location.getParent());
break;
case ZONE:
Location provider = location.getParent().getParent();
// zone can be a direct descendant of provider
if (provider == null)
provider = location.getParent();
assertProvider(provider);
break;
case HOST:
Location provider2 = location.getParent().getParent().getParent();
// zone can be a direct descendant of provider
if (provider2 == null)
provider2 = location.getParent().getParent();
assertProvider(provider2);
break;
case PROVIDER:
assertProvider(location);
break;
case REGION:
assertProvider(location.getParent());
break;
case ZONE:
Location provider = location.getParent().getParent();
// zone can be a direct descendant of provider
if (provider == null)
provider = location.getParent();
assertProvider(provider);
break;
case HOST:
Location provider2 = location.getParent().getParent().getParent();
// zone can be a direct descendant of provider
if (provider2 == null)
provider2 = location.getParent().getParent();
assertProvider(provider2);
break;
}
}
}
@ -621,7 +620,7 @@ public abstract class BaseComputeServiceLiveTest {
assertEquals(hello.getOutput().trim(), "hello");
ExecResponse exec = ssh.exec("java -version");
assert exec.getError().indexOf("1.6") != -1 || exec.getOutput().indexOf("1.6") != -1 : exec + "\n"
+ ssh.exec("cat /tmp/bootstrap/stdout.log /tmp/bootstrap/stderr.log");
+ ssh.exec("cat /tmp/bootstrap/stdout.log /tmp/bootstrap/stderr.log");
} finally {
if (ssh != null)
ssh.disconnect();

View File

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

View File

@ -19,6 +19,7 @@
package org.jclouds.compute.util;
import static org.jclouds.compute.util.ComputeServiceUtils.parseTagFromName;
import static org.testng.Assert.assertEquals;
import java.net.URI;
@ -38,6 +39,11 @@ import com.google.common.collect.ImmutableMultimap;
@Test(groups = "unit")
public class ComputeServiceUtilsTest {
@Test
public void testParseTagFromName() {
assertEquals(parseTagFromName("gogrid--849"), "gogrid-");
}
@Test
public void testExecHttpResponse() {
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
echo "export PATH=\"\$JAVA_HOME/bin/:\$PATH\"" >> /root/.bashrc
END_OF_SCRIPT
# add runscript footer

View File

@ -78,6 +78,11 @@
<artifactId>jersey-core</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-assistedinject</artifactId>
<version>3.0-rc2</version>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<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().is64Bit(), false);
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.getLocation().getId(), "us-east-1");
assertEquals(getCores(template.getHardware()), 1.0d);

View File

@ -50,9 +50,9 @@ public class GoGridTemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest {
@Override
public boolean apply(OsFamilyVersion64Bit input) {
return ((input.family == OsFamily.RHEL && !input.version.equals("5.4")) || //
(input.family == OsFamily.CENTOS && input.version.matches("5.[542]")) || //
(input.family == OsFamily.CENTOS && input.is64Bit && input.version.equals("5.[42]")) || //
(input.family == OsFamily.UBUNTU) || //
(input.family == OsFamily.CENTOS && input.version.matches("5.[542]")) || //
(input.family == OsFamily.CENTOS && input.is64Bit && input.version.equals("5.[42]")) || //
(input.family == OsFamily.UBUNTU) || //
(input.family == OsFamily.WINDOWS && input.version.equals("2008 SP2") || //
(input.family == OsFamily.WINDOWS && input.version.equals("2008 R2"))));
}

View File

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

View File

@ -19,11 +19,14 @@
package org.jclouds.slicehost.compute.config;
import static org.jclouds.compute.domain.OsFamily.UBUNTU;
import java.util.Set;
import javax.inject.Singleton;
import org.jclouds.compute.config.BaseComputeServiceContextModule;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.internal.BaseComputeService;
import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope;
@ -31,6 +34,7 @@ import org.jclouds.domain.internal.LocationImpl;
import org.jclouds.location.Provider;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Injector;
import com.google.inject.Provides;
/**
@ -39,6 +43,10 @@ import com.google.inject.Provides;
* @author Adrian Cole
*/
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
@Singleton

View File

@ -50,7 +50,7 @@ public class TerremarkVCloudExpressTemplateBuilderLiveTest extends BaseTemplateB
@Override
public boolean apply(OsFamilyVersion64Bit input) {
return ((input.family == OsFamily.RHEL || input.family == OsFamily.CENTOS) || //
(input.family == OsFamily.UBUNTU && !input.version.equals("9.10")) || //
(input.family == OsFamily.UBUNTU && !input.version.equals("9.10")) || //
(input.family == OsFamily.WINDOWS && (input.version.equals("2008 SP2") || input.version.equals("2008 R2"))));
}
@ -64,7 +64,6 @@ public class TerremarkVCloudExpressTemplateBuilderLiveTest extends BaseTemplateB
assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true);
assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU);
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>