move to using AtomicReference for retryable predicates saves at least one network call on re-fetch

This commit is contained in:
Adrian Cole 2012-02-14 23:18:25 +01:00
parent 2d5ef139ec
commit 384b8261ca
23 changed files with 611 additions and 171 deletions

View File

@ -24,10 +24,11 @@ import static com.google.common.collect.Iterables.transform;
import static org.jclouds.util.Preconditions2.checkNotEmpty; import static org.jclouds.util.Preconditions2.checkNotEmpty;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@ -71,8 +72,8 @@ import com.google.common.base.Predicate;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableMultimap.Builder; import com.google.common.collect.ImmutableMultimap.Builder;
import com.google.common.collect.ImmutableSet;
/** /**
* @author Adrian Cole * @author Adrian Cole
@ -91,9 +92,9 @@ public class EC2ComputeService extends BaseComputeService {
RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy, RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy,
ResumeNodeStrategy startNodeStrategy, SuspendNodeStrategy stopNodeStrategy, ResumeNodeStrategy startNodeStrategy, SuspendNodeStrategy stopNodeStrategy,
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider, Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider,
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning, @Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning,
@Named("NODE_TERMINATED") Predicate<NodeMetadata> nodeTerminated, @Named("NODE_TERMINATED") Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
@Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended, @Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,

View File

@ -26,6 +26,7 @@ import static org.jclouds.ec2.compute.util.EC2ComputeUtils.getZoneFromLocationOr
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
@ -80,7 +81,7 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
@VisibleForTesting @VisibleForTesting
final EC2Client client; final EC2Client client;
@VisibleForTesting @VisibleForTesting
final Predicate<NodeMetadata> nodeRunning; final Predicate<AtomicReference<NodeMetadata>> nodeRunning;
@VisibleForTesting @VisibleForTesting
final LoadingCache<RegionAndName, String> elasticIpCache; final LoadingCache<RegionAndName, String> elasticIpCache;
@VisibleForTesting @VisibleForTesting
@ -101,7 +102,7 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
EC2Client client, EC2Client client,
@Named("ELASTICIP") @Named("ELASTICIP")
LoadingCache<RegionAndName, String> elasticIpCache, LoadingCache<RegionAndName, String> elasticIpCache,
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning, @Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning,
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateBuilder> templateBuilderProvider,
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
InstancePresent instancePresent, Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata, InstancePresent instancePresent, Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
@ -197,7 +198,8 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
// block until instance is running // block until instance is running
logger.debug(">> awaiting status running instance(%s)", coordinates); logger.debug(">> awaiting status running instance(%s)", coordinates);
nodeRunning.apply(runningInstanceToNodeMetadata.apply(startedInstance)); AtomicReference<NodeMetadata> node = new AtomicReference<NodeMetadata>(runningInstanceToNodeMetadata.apply(startedInstance));
nodeRunning.apply(node);
logger.trace("<< running instance(%s)", coordinates); logger.trace("<< running instance(%s)", coordinates);
logger.debug(">> associating elastic IP %s to instance %s", ip, coordinates); logger.debug(">> associating elastic IP %s to instance %s", ip, coordinates);
client.getElasticIPAddressServices().associateAddressInRegion(region, ip, id); client.getElasticIPAddressServices().associateAddressInRegion(region, ip, id);

View File

@ -18,12 +18,12 @@
*/ */
package org.jclouds.ec2.compute.strategy; package org.jclouds.ec2.compute.strategy;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.eq; import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.reportMatcher; import static org.easymock.EasyMock.reportMatcher;
import static org.easymock.classextension.EasyMock.createMock; import static org.easymock.EasyMock.verify;
import static org.easymock.classextension.EasyMock.replay;
import static org.easymock.classextension.EasyMock.verify;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -33,8 +33,12 @@ import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.predicates.AtomicNodeRunning;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import org.jclouds.compute.util.ComputeUtils; import org.jclouds.compute.util.ComputeUtils;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
@ -50,9 +54,9 @@ import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.ec2.options.RunInstancesOptions; import org.jclouds.ec2.options.RunInstancesOptions;
import org.jclouds.ec2.services.ElasticIPAddressClient; import org.jclouds.ec2.services.ElasticIPAddressClient;
import org.jclouds.ec2.services.InstanceClient; import org.jclouds.ec2.services.InstanceClient;
import org.testng.Assert;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
@ -73,17 +77,19 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
String imageId = "ami1"; String imageId = "ami1";
String instanceCreatedId = "instance1"; String instanceCreatedId = "instance1";
NodeMetadata nodeMetadata = new NodeMetadataBuilder().id(region + "/" + instanceCreatedId)
.providerId(instanceCreatedId).state(NodeState.RUNNING).build();
// setup mocks // setup mocks
TemplateBuilder templateBuilder = createMock(TemplateBuilder.class); TemplateBuilder templateBuilder = createMock(TemplateBuilder.class);
EC2CreateNodesInGroupThenAddToSet strategy = setupStrategy(templateBuilder); EC2CreateNodesInGroupThenAddToSet strategy = setupStrategy(templateBuilder, nodeMetadata);
InputParams input = new InputParams(location); InputParams input = new InputParams(location);
InstanceClient instanceClient = createMock(InstanceClient.class); InstanceClient instanceClient = createMock(InstanceClient.class);
ElasticIPAddressClient ipClient = createMock(ElasticIPAddressClient.class); ElasticIPAddressClient ipClient = createMock(ElasticIPAddressClient.class);
RunInstancesOptions ec2Options = createMock(RunInstancesOptions.class); RunInstancesOptions ec2Options = createMock(RunInstancesOptions.class);
RunningInstance instance = createMock(RunningInstance.class); RunningInstance instance = createMock(RunningInstance.class);
Reservation<? extends RunningInstance> reservation = new Reservation<RunningInstance>(region, ImmutableSet Reservation<? extends RunningInstance> reservation = new Reservation<RunningInstance>(region,
.<String> of(), ImmutableSet.<RunningInstance> of(instance), "ownerId", "requesterId", "reservationId"); ImmutableSet.<String> of(), ImmutableSet.<RunningInstance> of(instance), "ownerId", "requesterId",
NodeMetadata nodeMetadata = createMock(NodeMetadata.class); "reservationId");
// enable auto-allocation // enable auto-allocation
strategy.autoAllocateElasticIps = true; strategy.autoAllocateElasticIps = true;
@ -93,8 +99,8 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
expect(templateBuilder.build()).andReturn(input.template); expect(templateBuilder.build()).andReturn(input.template);
expect(strategy.client.getInstanceServices()).andReturn(instanceClient).atLeastOnce(); expect(strategy.client.getInstanceServices()).andReturn(instanceClient).atLeastOnce();
expect( expect(
strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize.execute(region, input.tag, strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize
input.template)).andReturn(ec2Options); .execute(region, input.tag, input.template)).andReturn(ec2Options);
expect(strategy.client.getElasticIPAddressServices()).andReturn(ipClient).atLeastOnce(); expect(strategy.client.getElasticIPAddressServices()).andReturn(ipClient).atLeastOnce();
expect(input.template.getLocation()).andReturn(input.location).atLeastOnce(); expect(input.template.getLocation()).andReturn(input.location).atLeastOnce();
@ -104,12 +110,11 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
// differences when ip allocation // differences when ip allocation
expect(ipClient.allocateAddressInRegion(region)).andReturn("1.1.1.1"); expect(ipClient.allocateAddressInRegion(region)).andReturn("1.1.1.1");
expect(strategy.runningInstanceToNodeMetadata.apply(instance)).andReturn(nodeMetadata).atLeastOnce(); expect(strategy.runningInstanceToNodeMetadata.apply(instance)).andReturn(nodeMetadata).atLeastOnce();
expect(strategy.nodeRunning.apply(nodeMetadata)).andReturn(true);
ipClient.associateAddressInRegion(region, "1.1.1.1", instanceCreatedId); ipClient.associateAddressInRegion(region, "1.1.1.1", instanceCreatedId);
strategy.elasticIpCache.put(new RegionAndName(region, instanceCreatedId), "1.1.1.1"); strategy.elasticIpCache.put(new RegionAndName(region, instanceCreatedId), "1.1.1.1");
expect(instanceClient.runInstancesInRegion(region, zone, imageId, 1, input.count, ec2Options)).andReturn( expect(instanceClient.runInstancesInRegion(region, zone, imageId, 1, input.count, ec2Options)).andReturn(
Reservation.class.cast(reservation)); Reservation.class.cast(reservation));
expect(instance.getId()).andReturn(instanceCreatedId).atLeastOnce(); expect(instance.getId()).andReturn(instanceCreatedId).atLeastOnce();
// simulate a lazy credentials fetch // simulate a lazy credentials fetch
Credentials creds = new Credentials("foo", "bar"); Credentials creds = new Credentials("foo", "bar");
@ -121,9 +126,9 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
expect(input.template.getOptions()).andReturn(input.options).atLeastOnce(); expect(input.template.getOptions()).andReturn(input.options).atLeastOnce();
expect( expect(
strategy.utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(eq(input.options), strategy.utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(eq(input.options),
containsNodeMetadata(nodeMetadata), eq(input.nodes), eq(input.badNodes), containsNodeMetadata(nodeMetadata), eq(input.nodes), eq(input.badNodes), eq(input.customization)))
eq(input.customization))).andReturn(null); .andReturn(null);
// replay mocks // replay mocks
replay(templateBuilder); replay(templateBuilder);
@ -131,7 +136,6 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
replay(ipClient); replay(ipClient);
replay(ec2Options); replay(ec2Options);
replay(instance); replay(instance);
replay(nodeMetadata);
input.replayMe(); input.replayMe();
replayStrategy(strategy); replayStrategy(strategy);
@ -144,7 +148,6 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
verify(ipClient); verify(ipClient);
verify(ec2Options); verify(ec2Options);
verify(instance); verify(instance);
verify(nodeMetadata);
input.verifyMe(); input.verifyMe();
verifyStrategy(strategy); verifyStrategy(strategy);
} }
@ -184,29 +187,32 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
private void assertRegionAndZoneForLocation(Location location, String region, String zone) { private void assertRegionAndZoneForLocation(Location location, String region, String zone) {
String imageId = "ami1"; String imageId = "ami1";
String instanceCreatedId = "instance1"; String instanceCreatedId = "instance1";
NodeMetadata nodeMetadata = new NodeMetadataBuilder().id(region + "/" + instanceCreatedId)
.providerId(instanceCreatedId).state(NodeState.RUNNING).build();
// setup mocks // setup mocks
TemplateBuilder templateBuilder = createMock(TemplateBuilder.class); TemplateBuilder templateBuilder = createMock(TemplateBuilder.class);
EC2CreateNodesInGroupThenAddToSet strategy = setupStrategy(templateBuilder); EC2CreateNodesInGroupThenAddToSet strategy = setupStrategy(templateBuilder, nodeMetadata);
InputParams input = new InputParams(location); InputParams input = new InputParams(location);
InstanceClient instanceClient = createMock(InstanceClient.class); InstanceClient instanceClient = createMock(InstanceClient.class);
RunInstancesOptions ec2Options = createMock(RunInstancesOptions.class); RunInstancesOptions ec2Options = createMock(RunInstancesOptions.class);
RunningInstance instance = createMock(RunningInstance.class); RunningInstance instance = createMock(RunningInstance.class);
Reservation<? extends RunningInstance> reservation = new Reservation<RunningInstance>(region, ImmutableSet Reservation<? extends RunningInstance> reservation = new Reservation<RunningInstance>(region,
.<String> of(), ImmutableSet.<RunningInstance> of(instance), "ownerId", "requesterId", "reservationId"); ImmutableSet.<String> of(), ImmutableSet.<RunningInstance> of(instance), "ownerId", "requesterId",
NodeMetadata nodeMetadata = createMock(NodeMetadata.class); "reservationId");
// setup expectations // setup expectations
expect(templateBuilder.fromTemplate(input.template)).andReturn(templateBuilder); expect(templateBuilder.fromTemplate(input.template)).andReturn(templateBuilder);
expect(templateBuilder.build()).andReturn(input.template); expect(templateBuilder.build()).andReturn(input.template);
expect(strategy.client.getInstanceServices()).andReturn(instanceClient).atLeastOnce(); expect(strategy.client.getInstanceServices()).andReturn(instanceClient).atLeastOnce();
expect( expect(
strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize.execute(region, input.tag, strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize
input.template)).andReturn(ec2Options); .execute(region, input.tag, input.template)).andReturn(ec2Options);
expect(input.template.getLocation()).andReturn(input.location).atLeastOnce(); expect(input.template.getLocation()).andReturn(input.location).atLeastOnce();
expect(input.template.getImage()).andReturn(input.image).atLeastOnce(); expect(input.template.getImage()).andReturn(input.image).atLeastOnce();
expect(input.image.getProviderId()).andReturn(imageId).atLeastOnce(); expect(input.image.getProviderId()).andReturn(imageId).atLeastOnce();
expect(instanceClient.runInstancesInRegion(region, zone, imageId, 1, input.count, ec2Options)).andReturn( expect(instanceClient.runInstancesInRegion(region, zone, imageId, 1, input.count, ec2Options)).andReturn(
Reservation.class.cast(reservation)); Reservation.class.cast(reservation));
expect(instance.getId()).andReturn(instanceCreatedId).atLeastOnce(); expect(instance.getId()).andReturn(instanceCreatedId).atLeastOnce();
// simulate a lazy credentials fetch // simulate a lazy credentials fetch
Credentials creds = new Credentials("foo", "bar"); Credentials creds = new Credentials("foo", "bar");
@ -219,16 +225,15 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
expect(strategy.runningInstanceToNodeMetadata.apply(instance)).andReturn(nodeMetadata); expect(strategy.runningInstanceToNodeMetadata.apply(instance)).andReturn(nodeMetadata);
expect( expect(
strategy.utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(eq(input.options), strategy.utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(eq(input.options),
containsNodeMetadata(nodeMetadata), eq(input.nodes), eq(input.badNodes), containsNodeMetadata(nodeMetadata), eq(input.nodes), eq(input.badNodes), eq(input.customization)))
eq(input.customization))).andReturn(null); .andReturn(null);
// replay mocks // replay mocks
replay(templateBuilder); replay(templateBuilder);
replay(instanceClient); replay(instanceClient);
replay(ec2Options); replay(ec2Options);
replay(instance); replay(instance);
replay(nodeMetadata);
input.replayMe(); input.replayMe();
replayStrategy(strategy); replayStrategy(strategy);
@ -240,16 +245,16 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
verify(instanceClient); verify(instanceClient);
verify(ec2Options); verify(ec2Options);
verify(instance); verify(instance);
verify(nodeMetadata);
input.verifyMe(); input.verifyMe();
verifyStrategy(strategy); verifyStrategy(strategy);
} }
private static final Location REGION_AP_SOUTHEAST_1 = new LocationBuilder().scope(LocationScope.REGION).id( private static final Location REGION_AP_SOUTHEAST_1 = new LocationBuilder().scope(LocationScope.REGION)
"ap-southeast-1").description("ap-southeast-1").parent( .id("ap-southeast-1").description("ap-southeast-1")
new LocationBuilder().scope(LocationScope.PROVIDER).id("aws-ec2").description("aws-ec2").build()).build(); .parent(new LocationBuilder().scope(LocationScope.PROVIDER).id("aws-ec2").description("aws-ec2").build())
private static final Location ZONE_AP_SOUTHEAST_1A = new LocationBuilder().scope(LocationScope.ZONE).id( .build();
"ap-southeast-1a").description("ap-southeast-1a").parent(REGION_AP_SOUTHEAST_1).build(); private static final Location ZONE_AP_SOUTHEAST_1A = new LocationBuilder().scope(LocationScope.ZONE)
.id("ap-southeast-1a").description("ap-southeast-1a").parent(REGION_AP_SOUTHEAST_1).build();
// ///////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -293,7 +298,6 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
private void verifyStrategy(EC2CreateNodesInGroupThenAddToSet strategy) { private void verifyStrategy(EC2CreateNodesInGroupThenAddToSet strategy) {
verify(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize); verify(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize);
verify(strategy.client); verify(strategy.client);
verify(strategy.nodeRunning);
verify(strategy.elasticIpCache); verify(strategy.elasticIpCache);
verify(strategy.instancePresent); verify(strategy.instancePresent);
verify(strategy.runningInstanceToNodeMetadata); verify(strategy.runningInstanceToNodeMetadata);
@ -303,26 +307,33 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private EC2CreateNodesInGroupThenAddToSet setupStrategy(TemplateBuilder template) { private EC2CreateNodesInGroupThenAddToSet setupStrategy(TemplateBuilder template, final NodeMetadata node) {
EC2Client client = createMock(EC2Client.class); EC2Client client = createMock(EC2Client.class);
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = createMock(CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.class); CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = createMock(CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.class);
InstancePresent instancePresent = createMock(InstancePresent.class); InstancePresent instancePresent = createMock(InstancePresent.class);
RunningInstanceToNodeMetadata runningInstanceToNodeMetadata = createMock(RunningInstanceToNodeMetadata.class); RunningInstanceToNodeMetadata runningInstanceToNodeMetadata = createMock(RunningInstanceToNodeMetadata.class);
LoadingCache<RunningInstance, Credentials> instanceToCredentials = createMock(LoadingCache.class); LoadingCache<RunningInstance, Credentials> instanceToCredentials = createMock(LoadingCache.class);
LoadingCache<RegionAndName, String> elasticIpCache = createMock(LoadingCache.class); LoadingCache<RegionAndName, String> elasticIpCache = createMock(LoadingCache.class);
Predicate<NodeMetadata> nodeRunning = createMock(Predicate.class); GetNodeMetadataStrategy nodeRunning = new GetNodeMetadataStrategy(){
@Override
public NodeMetadata getNode(String input) {
Assert.assertEquals(input, node.getId());
return node;
}
};
Map<String, Credentials> credentialStore = createMock(Map.class); Map<String, Credentials> credentialStore = createMock(Map.class);
ComputeUtils utils = createMock(ComputeUtils.class); ComputeUtils utils = createMock(ComputeUtils.class);
return new EC2CreateNodesInGroupThenAddToSet(client, elasticIpCache, nodeRunning, Providers return new EC2CreateNodesInGroupThenAddToSet(client, elasticIpCache, new AtomicNodeRunning(nodeRunning),
.<TemplateBuilder> of(template), createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, Providers.<TemplateBuilder> of(template), createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
instancePresent, runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils); instancePresent, runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils);
} }
private void replayStrategy(EC2CreateNodesInGroupThenAddToSet strategy) { private void replayStrategy(EC2CreateNodesInGroupThenAddToSet strategy) {
replay(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize); replay(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize);
replay(strategy.client); replay(strategy.client);
replay(strategy.elasticIpCache); replay(strategy.elasticIpCache);
replay(strategy.nodeRunning);
replay(strategy.instancePresent); replay(strategy.instancePresent);
replay(strategy.runningInstanceToNodeMetadata); replay(strategy.runningInstanceToNodeMetadata);
replay(strategy.instanceToCredentials); replay(strategy.instanceToCredentials);

View File

@ -21,6 +21,7 @@ package org.jclouds.trmk.vcloud_0_8.compute;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@ -71,9 +72,9 @@ public class TerremarkVCloudComputeService extends BaseComputeService {
RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy, RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy,
ResumeNodeStrategy resumeNodeStrategy, SuspendNodeStrategy suspendNodeStrategy, ResumeNodeStrategy resumeNodeStrategy, SuspendNodeStrategy suspendNodeStrategy,
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider, Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider,
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning, @Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning,
@Named("NODE_TERMINATED") Predicate<NodeMetadata> nodeTerminated, @Named("NODE_TERMINATED") Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
@Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended, @Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,

View File

@ -103,7 +103,7 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule {
install(new FactoryModuleBuilder().implement(new TypeLiteral<Callable<Void>>() { install(new FactoryModuleBuilder().implement(new TypeLiteral<Callable<Void>>() {
}, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.class) }, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.class)
.implement(new TypeLiteral<Function<NodeMetadata, Void>>() { .implement(new TypeLiteral<Function<AtomicReference<NodeMetadata>, Void>>() {
}, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.class) }, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.class)
.build(CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory.class)); .build(CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory.class));

View File

@ -20,10 +20,13 @@ package org.jclouds.compute.config;
import static com.google.common.base.Predicates.not; import static com.google.common.base.Predicates.not;
import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.predicates.AtomicNodeRunning;
import org.jclouds.compute.predicates.NodeRunning; import org.jclouds.compute.predicates.NodeRunning;
import org.jclouds.compute.predicates.NodeSuspended; import org.jclouds.compute.predicates.NodeSuspended;
import org.jclouds.compute.predicates.NodeTerminated; import org.jclouds.compute.predicates.NodeTerminated;
@ -46,6 +49,32 @@ public class ComputeServiceTimeoutsModule extends AbstractModule {
@Provides @Provides
@Singleton @Singleton
@Named("NODE_RUNNING") @Named("NODE_RUNNING")
protected Predicate<AtomicReference<NodeMetadata>> nodeRunning(AtomicNodeRunning stateRunning, Timeouts timeouts) {
return timeouts.nodeRunning == 0 ? stateRunning : new RetryablePredicate<AtomicReference<NodeMetadata>>(stateRunning,
timeouts.nodeRunning);
}
@Provides
@Singleton
@Named("NODE_TERMINATED")
protected Predicate<AtomicReference<NodeMetadata>> serverTerminated(AtomicNodeRunning stateTerminated, Timeouts timeouts) {
return timeouts.nodeTerminated == 0 ? stateTerminated : new RetryablePredicate<AtomicReference<NodeMetadata>>(stateTerminated,
timeouts.nodeTerminated);
}
@Provides
@Singleton
@Named("NODE_SUSPENDED")
protected Predicate<AtomicReference<NodeMetadata>> serverSuspended(AtomicNodeRunning stateSuspended, Timeouts timeouts) {
return timeouts.nodeSuspended == 0 ? stateSuspended : new RetryablePredicate<AtomicReference<NodeMetadata>>(stateSuspended,
timeouts.nodeSuspended);
}
@Provides
@Singleton
@Named("NODE_RUNNING")
@Deprecated
protected Predicate<NodeMetadata> nodeRunning(NodeRunning stateRunning, Timeouts timeouts) { protected Predicate<NodeMetadata> nodeRunning(NodeRunning stateRunning, Timeouts timeouts) {
return timeouts.nodeRunning == 0 ? stateRunning : new RetryablePredicate<NodeMetadata>(stateRunning, return timeouts.nodeRunning == 0 ? stateRunning : new RetryablePredicate<NodeMetadata>(stateRunning,
timeouts.nodeRunning); timeouts.nodeRunning);
@ -54,6 +83,7 @@ public class ComputeServiceTimeoutsModule extends AbstractModule {
@Provides @Provides
@Singleton @Singleton
@Named("NODE_TERMINATED") @Named("NODE_TERMINATED")
@Deprecated
protected Predicate<NodeMetadata> serverTerminated(NodeTerminated stateTerminated, Timeouts timeouts) { protected Predicate<NodeMetadata> serverTerminated(NodeTerminated stateTerminated, Timeouts timeouts) {
return timeouts.nodeTerminated == 0 ? stateTerminated : new RetryablePredicate<NodeMetadata>(stateTerminated, return timeouts.nodeTerminated == 0 ? stateTerminated : new RetryablePredicate<NodeMetadata>(stateTerminated,
timeouts.nodeTerminated); timeouts.nodeTerminated);
@ -63,6 +93,7 @@ public class ComputeServiceTimeoutsModule extends AbstractModule {
@Provides @Provides
@Singleton @Singleton
@Named("NODE_SUSPENDED") @Named("NODE_SUSPENDED")
@Deprecated
protected Predicate<NodeMetadata> serverSuspended(NodeSuspended stateSuspended, Timeouts timeouts) { protected Predicate<NodeMetadata> serverSuspended(NodeSuspended stateSuspended, Timeouts timeouts) {
return timeouts.nodeSuspended == 0 ? stateSuspended : new RetryablePredicate<NodeMetadata>(stateSuspended, return timeouts.nodeSuspended == 0 ? stateSuspended : new RetryablePredicate<NodeMetadata>(stateSuspended,
timeouts.nodeSuspended); timeouts.nodeSuspended);

View File

@ -125,9 +125,9 @@ public class BaseComputeService implements ComputeService {
private final SuspendNodeStrategy suspendNodeStrategy; private final SuspendNodeStrategy suspendNodeStrategy;
private final Provider<TemplateBuilder> templateBuilderProvider; private final Provider<TemplateBuilder> templateBuilderProvider;
private final Provider<TemplateOptions> templateOptionsProvider; private final Provider<TemplateOptions> templateOptionsProvider;
private final Predicate<NodeMetadata> nodeRunning; private final Predicate<AtomicReference<NodeMetadata>> nodeRunning;
private final Predicate<NodeMetadata> nodeTerminated; private final Predicate<AtomicReference<NodeMetadata>> nodeTerminated;
private final Predicate<NodeMetadata> nodeSuspended; private final Predicate<AtomicReference<NodeMetadata>> nodeSuspended;
private final InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory; private final InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory;
private final Timeouts timeouts; private final Timeouts timeouts;
private final InitAdminAccess initAdminAccess; private final InitAdminAccess initAdminAccess;
@ -143,9 +143,9 @@ public class BaseComputeService implements ComputeService {
RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy, RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy,
ResumeNodeStrategy resumeNodeStrategy, SuspendNodeStrategy suspendNodeStrategy, ResumeNodeStrategy resumeNodeStrategy, SuspendNodeStrategy suspendNodeStrategy,
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider, Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider,
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning, @Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning,
@Named("NODE_TERMINATED") Predicate<NodeMetadata> nodeTerminated, @Named("NODE_TERMINATED") Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
@Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended, @Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess,
RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials, RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials,
Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) { Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
@ -285,7 +285,7 @@ public class BaseComputeService implements ComputeService {
}, timeouts.nodeRunning, 1000, TimeUnit.MILLISECONDS); }, timeouts.nodeRunning, 1000, TimeUnit.MILLISECONDS);
boolean successful = tester.apply(id) && (node.get() == null || nodeTerminated.apply(node.get())); boolean successful = tester.apply(id) && (node.get() == null || nodeTerminated.apply(node));
if (successful) if (successful)
credentialStore.remove("node#" + id); credentialStore.remove("node#" + id);
logger.debug("<< destroyed node(%s) success(%s)", id, successful); logger.debug("<< destroyed node(%s) success(%s)", id, successful);
@ -383,7 +383,7 @@ public class BaseComputeService implements ComputeService {
public void rebootNode(String id) { public void rebootNode(String id) {
checkNotNull(id, "id"); checkNotNull(id, "id");
logger.debug(">> rebooting node(%s)", id); logger.debug(">> rebooting node(%s)", id);
NodeMetadata node = rebootNodeStrategy.rebootNode(id); AtomicReference<NodeMetadata> node = new AtomicReference<NodeMetadata>(rebootNodeStrategy.rebootNode(id));
boolean successful = nodeRunning.apply(node); boolean successful = nodeRunning.apply(node);
logger.debug("<< rebooted node(%s) success(%s)", id, successful); logger.debug("<< rebooted node(%s) success(%s)", id, successful);
} }
@ -414,7 +414,7 @@ public class BaseComputeService implements ComputeService {
public void resumeNode(String id) { public void resumeNode(String id) {
checkNotNull(id, "id"); checkNotNull(id, "id");
logger.debug(">> resuming node(%s)", id); logger.debug(">> resuming node(%s)", id);
NodeMetadata node = resumeNodeStrategy.resumeNode(id); AtomicReference<NodeMetadata> node = new AtomicReference<NodeMetadata>(resumeNodeStrategy.resumeNode(id));
boolean successful = nodeRunning.apply(node); boolean successful = nodeRunning.apply(node);
logger.debug("<< resumed node(%s) success(%s)", id, successful); logger.debug("<< resumed node(%s) success(%s)", id, successful);
} }
@ -445,7 +445,7 @@ public class BaseComputeService implements ComputeService {
public void suspendNode(String id) { public void suspendNode(String id) {
checkNotNull(id, "id"); checkNotNull(id, "id");
logger.debug(">> suspending node(%s)", id); logger.debug(">> suspending node(%s)", id);
NodeMetadata node = suspendNodeStrategy.suspendNode(id); AtomicReference<NodeMetadata> node = new AtomicReference<NodeMetadata>(suspendNodeStrategy.suspendNode(id));
boolean successful = nodeSuspended.apply(node); boolean successful = nodeSuspended.apply(node);
logger.debug("<< suspended node(%s) success(%s)", id, successful); logger.debug("<< suspended node(%s) success(%s)", id, successful);
} }

View File

@ -0,0 +1,42 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.compute.predicates;
import javax.inject.Singleton;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject;
/**
*
* Tests to see if a node is running.
*
* @author Adrian Cole
*/
@Singleton
public class AtomicNodeRunning extends RefreshAndDoubleCheckOnFailUnlessStateInvalid {
@Inject
public AtomicNodeRunning(GetNodeMetadataStrategy client) {
super(NodeState.RUNNING, ImmutableSet.of(NodeState.ERROR, NodeState.TERMINATED), client);
}
}

View File

@ -0,0 +1,41 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.compute.predicates;
import javax.inject.Singleton;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import com.google.inject.Inject;
/**
*
* Tests to see if a node is suspended.
*
* @author Adrian Cole
*/
@Singleton
public class AtomicNodeSuspended extends RefreshAndDoubleCheckOnFailUnlessStateInvalid {
@Inject
public AtomicNodeSuspended(GetNodeMetadataStrategy client) {
super(NodeState.SUSPENDED, client);
}
}

View File

@ -39,7 +39,9 @@ import com.google.inject.Inject;
* Tests to see if a node is active. * Tests to see if a node is active.
* *
* @author Adrian Cole * @author Adrian Cole
* @see RefreshAndDoubleCheckOnFailUnlessStateInvalid
*/ */
@Deprecated
@Singleton @Singleton
public class NodePresentAndInIntendedState implements Predicate<NodeMetadata> { public class NodePresentAndInIntendedState implements Predicate<NodeMetadata> {

View File

@ -31,8 +31,10 @@ import com.google.inject.Inject;
* Tests to see if a node is running. * Tests to see if a node is running.
* *
* @author Adrian Cole * @author Adrian Cole
* @see AtomicNodeRunning
*/ */
@Singleton @Singleton
@Deprecated
public class NodeRunning extends NodePresentAndInIntendedState { public class NodeRunning extends NodePresentAndInIntendedState {
@Inject @Inject

View File

@ -30,8 +30,10 @@ import com.google.inject.Inject;
* Tests to see if a node is suspended. * Tests to see if a node is suspended.
* *
* @author Adrian Cole * @author Adrian Cole
* @see AtomicNodeSuspended
*/ */
@Singleton @Singleton
@Deprecated
public class NodeSuspended extends NodePresentAndInIntendedState { public class NodeSuspended extends NodePresentAndInIntendedState {
@Inject @Inject

View File

@ -36,8 +36,10 @@ import com.google.inject.Inject;
* Tests to see if a node is deleted * Tests to see if a node is deleted
* *
* @author Adrian Cole * @author Adrian Cole
* @see TrueIfNullOrTerminatedRefreshAndDoubleCheckOnFalse
*/ */
@Singleton @Singleton
@Deprecated
public class NodeTerminated implements Predicate<NodeMetadata> { public class NodeTerminated implements Predicate<NodeMetadata> {
private final GetNodeMetadataStrategy client; private final GetNodeMetadataStrategy client;

View File

@ -0,0 +1,86 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.compute.predicates;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Resource;
import javax.inject.Singleton;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import org.jclouds.logging.Logger;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject;
/**
*
* Tests to see if a node is active.
*
* @author Adrian Cole
*/
@Singleton
public class RefreshAndDoubleCheckOnFailUnlessStateInvalid implements Predicate<AtomicReference<NodeMetadata>> {
private final GetNodeMetadataStrategy client;
private final NodeState intended;
private final Set<NodeState> invalids;
@Resource
protected Logger logger = Logger.NULL;
@Inject
public RefreshAndDoubleCheckOnFailUnlessStateInvalid(NodeState intended, GetNodeMetadataStrategy client) {
this(intended, ImmutableSet.of(NodeState.ERROR), client);
}
public RefreshAndDoubleCheckOnFailUnlessStateInvalid(NodeState intended, Set<NodeState> invalids, GetNodeMetadataStrategy client) {
this.intended = intended;
this.client = client;
this.invalids = invalids;
}
public boolean apply(AtomicReference<NodeMetadata> atomicNode) {
NodeMetadata node = atomicNode.get();
if (checkState(node))
return true;
node = refresh(node);
atomicNode.set(node);
return checkState(node);
}
public boolean checkState(NodeMetadata node) {
if (node == null)
return false;
logger.trace("%s: looking for node state %s: currently: %s", node.getId(), intended, node.getState());
if (invalids.contains(node.getState()))
throw new IllegalStateException("node " + node.getId() + " in location " + node.getLocation()
+ " is in invalid state "+node.getState());
return node.getState() == intended;
}
private NodeMetadata refresh(NodeMetadata node) {
if (node == null || node.getId() == null)
return null;
return client.getNode(node.getId());
}
}

View File

@ -0,0 +1,69 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.compute.predicates;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Resource;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import org.jclouds.logging.Logger;
import com.google.common.base.Predicate;
import com.google.inject.Inject;
/**
*
*
* @author Adrian Cole
*/
public class TrueIfNullOrTerminatedRefreshAndDoubleCheckOnFalse implements Predicate<AtomicReference<NodeMetadata>> {
private final GetNodeMetadataStrategy client;
@Resource
protected Logger logger = Logger.NULL;
@Inject
public TrueIfNullOrTerminatedRefreshAndDoubleCheckOnFalse(GetNodeMetadataStrategy client) {
this.client = client;
}
public boolean apply(AtomicReference<NodeMetadata> atomicNode) {
NodeMetadata node = atomicNode.get();
if (checkState(node))
return true;
node = refresh(node);
atomicNode.set(node);
return checkState(node);
}
public boolean checkState(NodeMetadata node) {
if (node == null)
return true;
logger.trace("%s: looking for node state %s: currently: %s", node.getId(), NodeState.TERMINATED, node.getState());
return node.getState() == NodeState.TERMINATED;
}
private NodeMetadata refresh(NodeMetadata node) {
return client.getNode(node.getId());
}
}

View File

@ -27,8 +27,8 @@ import static org.jclouds.compute.util.ComputeServiceUtils.findReachableSocketOn
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicReference;
import org.jclouds.javax.annotation.Nullable;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Named; import javax.inject.Named;
@ -41,6 +41,7 @@ import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen; import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
@ -55,31 +56,28 @@ import com.google.inject.assistedinject.AssistedInject;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Callable<Void>, public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Callable<Void>,
Function<NodeMetadata, Void> { Function<AtomicReference<NodeMetadata>, Void> {
public static interface Factory { public static interface Factory {
Callable<Void> create(TemplateOptions options, NodeMetadata node, Set<NodeMetadata> goodNodes, Callable<Void> create(TemplateOptions options, AtomicReference<NodeMetadata> node, Set<NodeMetadata> goodNodes,
Map<NodeMetadata, Exception> badNodes, Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses);
Multimap<NodeMetadata, CustomizationResponse> customizationResponses);
Function<NodeMetadata, Void> create(TemplateOptions options, Set<NodeMetadata> goodNodes, Function<AtomicReference<NodeMetadata>, Void> create(TemplateOptions options, Set<NodeMetadata> goodNodes,
Map<NodeMetadata, Exception> badNodes, Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses);
Multimap<NodeMetadata, CustomizationResponse> customizationResponses);
} }
@Resource @Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER) @Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
private final Predicate<NodeMetadata> nodeRunning; private final Predicate<AtomicReference<NodeMetadata>> nodeRunning;
private final InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory; private final InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory;
private final GetNodeMetadataStrategy getNode;
private final RetryIfSocketNotYetOpen socketTester; private final RetryIfSocketNotYetOpen socketTester;
private final Timeouts timeouts; private final Timeouts timeouts;
@Nullable @Nullable
private final Statement statement; private final Statement statement;
private final TemplateOptions options; private final TemplateOptions options;
private NodeMetadata node; private AtomicReference<NodeMetadata> node;
private final Set<NodeMetadata> goodNodes; private final Set<NodeMetadata> goodNodes;
private final Map<NodeMetadata, Exception> badNodes; private final Map<NodeMetadata, Exception> badNodes;
private final Multimap<NodeMetadata, CustomizationResponse> customizationResponses; private final Multimap<NodeMetadata, CustomizationResponse> customizationResponses;
@ -88,18 +86,17 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal
@AssistedInject @AssistedInject
public CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap( public CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning, GetNodeMetadataStrategy getNode, @Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning,
RetryIfSocketNotYetOpen socketTester, Timeouts timeouts, RetryIfSocketNotYetOpen socketTester, Timeouts timeouts,
Function<TemplateOptions, Statement> templateOptionsToStatement, Function<TemplateOptions, Statement> templateOptionsToStatement,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, @Assisted TemplateOptions options,
@Assisted TemplateOptions options, @Assisted @Nullable NodeMetadata node, @Assisted AtomicReference<NodeMetadata> node, @Assisted Set<NodeMetadata> goodNodes,
@Assisted Set<NodeMetadata> goodNodes, @Assisted Map<NodeMetadata, Exception> badNodes, @Assisted Map<NodeMetadata, Exception> badNodes,
@Assisted Multimap<NodeMetadata, CustomizationResponse> customizationResponses) { @Assisted Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
this.statement = checkNotNull(templateOptionsToStatement, "templateOptionsToStatement").apply( this.statement = checkNotNull(templateOptionsToStatement, "templateOptionsToStatement").apply(
checkNotNull(options, "options")); checkNotNull(options, "options"));
this.nodeRunning = checkNotNull(nodeRunning, "nodeRunning"); this.nodeRunning = checkNotNull(nodeRunning, "nodeRunning");
this.initScriptRunnerFactory = checkNotNull(initScriptRunnerFactory, "initScriptRunnerFactory"); this.initScriptRunnerFactory = checkNotNull(initScriptRunnerFactory, "initScriptRunnerFactory");
this.getNode = checkNotNull(getNode, "getNode");
this.socketTester = checkNotNull(socketTester, "socketTester"); this.socketTester = checkNotNull(socketTester, "socketTester");
this.timeouts = checkNotNull(timeouts, "timeouts"); this.timeouts = checkNotNull(timeouts, "timeouts");
this.node = node; this.node = node;
@ -111,61 +108,65 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal
@AssistedInject @AssistedInject
public CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap( public CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning, GetNodeMetadataStrategy getNode, @Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning, GetNodeMetadataStrategy getNode,
RetryIfSocketNotYetOpen socketTester, Timeouts timeouts, RetryIfSocketNotYetOpen socketTester, Timeouts timeouts,
Function<TemplateOptions, Statement> templateOptionsToStatement, Function<TemplateOptions, Statement> templateOptionsToStatement,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, @Assisted TemplateOptions options,
@Assisted TemplateOptions options, @Assisted Set<NodeMetadata> goodNodes, @Assisted Set<NodeMetadata> goodNodes, @Assisted Map<NodeMetadata, Exception> badNodes,
@Assisted Map<NodeMetadata, Exception> badNodes, @Assisted Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
@Assisted Multimap<NodeMetadata, CustomizationResponse> customizationResponses) { this(nodeRunning, socketTester, timeouts, templateOptionsToStatement, initScriptRunnerFactory, options,
this(nodeRunning, getNode, socketTester, timeouts, templateOptionsToStatement, initScriptRunnerFactory, options, new AtomicReference<NodeMetadata>(null), goodNodes, badNodes, customizationResponses);
null, goodNodes, badNodes, customizationResponses);
} }
@Override @Override
public Void call() { public Void call() {
checkState(!tainted, "this object is not designed to be reused: %s", toString()); checkState(!tainted, "this object is not designed to be reused: %s", toString());
tainted = true; tainted = true;
String originalId = node.getId(); String originalId = node.get().getId();
NodeMetadata originalNode = node; NodeMetadata originalNode = node.get();
try { try {
if (options.shouldBlockUntilRunning()) { if (options.shouldBlockUntilRunning()) {
if (nodeRunning.apply(node)) { try {
node = getNode.getNode(originalId); if (!nodeRunning.apply(node)) {
} else { if (node.get() == null) {
NodeMetadata nodeForState = getNode.getNode(originalId); node.set(originalNode);
NodeState state = nodeForState == null ? NodeState.TERMINATED : nodeForState.getState(); throw new IllegalStateException(format("api response for node(%s) was null, so we can't customize",
if (state == NodeState.TERMINATED) originalId));
}
throw new IllegalStateException(
format(
"node(%s) didn't achieve the state running within %d seconds, so we couldn't customize; final state: %s",
originalId, timeouts.nodeRunning / 1000, node.get().getState()));
}
} catch (IllegalStateException e) {
if (node.get().getState() == NodeState.TERMINATED) {
throw new IllegalStateException(format("node(%s) terminated before we could customize", originalId)); throw new IllegalStateException(format("node(%s) terminated before we could customize", originalId));
else } else {
throw new IllegalStateException(format( throw e;
"node(%s) didn't achieve the state running within %d seconds, final state: %s", originalId, }
timeouts.nodeRunning / 1000, state));
} }
if (node == null)
throw new IllegalStateException(format("node %s terminated before applying options", originalId));
if (statement != null) { if (statement != null) {
RunScriptOnNode runner = initScriptRunnerFactory.create(node, statement, options, badNodes).call(); RunScriptOnNode runner = initScriptRunnerFactory.create(node.get(), statement, options, badNodes).call();
if (runner != null) { if (runner != null) {
ExecResponse exec = runner.call(); ExecResponse exec = runner.call();
customizationResponses.put(node, exec); customizationResponses.put(node.get(), exec);
} }
} }
if (options.getPort() > 0) { if (options.getPort() > 0) {
findReachableSocketOnNode(socketTester.seconds(options.getSeconds()), node, options.getPort()); findReachableSocketOnNode(socketTester.seconds(options.getSeconds()), node.get(), options.getPort());
} }
} }
logger.debug("<< options applied node(%s)", originalId); logger.debug("<< customized node(%s)", originalId);
goodNodes.add(node); goodNodes.add(node.get());
} catch (Exception e) { } catch (Exception e) {
logger.error(e, "<< problem applying options to node(%s): ", originalId, getRootCause(e).getMessage()); logger.error(e, "<< problem customizing node(%s): ", originalId, getRootCause(e).getMessage());
badNodes.put(node == null ? originalNode : node, e); badNodes.put(node.get(), e);
} }
return null; return null;
} }
@Override @Override
public Void apply(NodeMetadata input) { public Void apply(AtomicReference<NodeMetadata> input) {
this.node = input; this.node = input;
call(); call();
return null; return null;

View File

@ -31,6 +31,7 @@ import java.util.Set;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
@ -60,7 +61,7 @@ import com.google.common.collect.Multimap;
@Singleton @Singleton
public class CreateNodesWithGroupEncodedIntoNameThenAddToSet implements CreateNodesInGroupThenAddToSet { public class CreateNodesWithGroupEncodedIntoNameThenAddToSet implements CreateNodesInGroupThenAddToSet {
private class AddNode implements Callable<NodeMetadata> { private class AddNode implements Callable<AtomicReference<NodeMetadata>> {
private final String name; private final String name;
private final String group; private final String group;
private final Template template; private final Template template;
@ -72,14 +73,14 @@ public class CreateNodesWithGroupEncodedIntoNameThenAddToSet implements CreateNo
} }
@Override @Override
public NodeMetadata call() throws Exception { public AtomicReference<NodeMetadata> call() throws Exception {
NodeMetadata node = null; NodeMetadata node = null;
logger.debug(">> adding node location(%s) name(%s) image(%s) hardware(%s)", logger.debug(">> adding node location(%s) name(%s) image(%s) hardware(%s)",
template.getLocation().getId(), name, template.getImage().getProviderId(), template.getHardware() template.getLocation().getId(), name, template.getImage().getProviderId(), template.getHardware()
.getProviderId()); .getProviderId());
node = addNodeWithGroupStrategy.createNodeWithGroupEncodedIntoName(group, name, template); node = addNodeWithGroupStrategy.createNodeWithGroupEncodedIntoName(group, name, template);
logger.debug("<< %s node(%s)", node.getState(), node.getId()); logger.debug("<< %s node(%s)", node.getState(), node.getId());
return node; return new AtomicReference<NodeMetadata>(node);
} }
public String toString() { public String toString() {

View File

@ -24,6 +24,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@ -60,7 +61,7 @@ public class ComputeUtils {
Map<NodeMetadata, Future<Void>> responses = newLinkedHashMap(); Map<NodeMetadata, Future<Void>> responses = newLinkedHashMap();
for (NodeMetadata node : runningNodes) { for (NodeMetadata node : runningNodes) {
responses.put(node, executor.submit(customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory.create( responses.put(node, executor.submit(customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory.create(
options, node, goodNodes, badNodes, customizationResponses))); options, new AtomicReference<NodeMetadata>(node), goodNodes, badNodes, customizationResponses)));
} }
return responses; return responses;
} }

View File

@ -0,0 +1,144 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.compute.predicates;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import java.util.concurrent.atomic.AtomicReference;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
/**
* Tests possible uses of NodePredicates
*
* @author Aled Sage, Adrian Cole
*/
@Test(singleThreaded = true, testName = "AtomicNodePredicatesTest")
public class AtomicNodePredicatesTest {
private NodeMetadata node;
private GetNodeMetadataStrategy computeService;
@Test
public void testNoUpdatesAtomicReferenceOnPass() {
NodeMetadata running = new NodeMetadataBuilder().id("myid").state(NodeState.RUNNING).build();
GetNodeMetadataStrategy computeService = createMock(GetNodeMetadataStrategy.class);
replay(computeService);
AtomicNodeRunning nodeRunning = new AtomicNodeRunning(computeService);
AtomicReference<NodeMetadata> reference = new AtomicReference<NodeMetadata>(running);
Assert.assertTrue(nodeRunning.apply(reference));
Assert.assertEquals(reference.get(), running);
verify(computeService);
}
@Test
public void testRefreshUpdatesAtomicReferenceOnRecheckPending() {
NodeMetadata pending = new NodeMetadataBuilder().id("myid").state(NodeState.PENDING).build();
GetNodeMetadataStrategy computeService = createMock(GetNodeMetadataStrategy.class);
expect(computeService.getNode("myid")).andReturn(pending);
replay(computeService);
AtomicNodeRunning nodeRunning = new AtomicNodeRunning(computeService);
AtomicReference<NodeMetadata> reference = new AtomicReference<NodeMetadata>(pending);
Assert.assertFalse(nodeRunning.apply(reference));
Assert.assertEquals(reference.get(), pending);
verify(computeService);
}
@Test
public void testRefreshUpdatesAtomicReferenceOnRecheckRunning() {
NodeMetadata running = new NodeMetadataBuilder().id("myid").state(NodeState.RUNNING).build();
NodeMetadata pending = new NodeMetadataBuilder().id("myid").state(NodeState.PENDING).build();
GetNodeMetadataStrategy computeService = createMock(GetNodeMetadataStrategy.class);
expect(computeService.getNode("myid")).andReturn(running);
replay(computeService);
AtomicNodeRunning nodeRunning = new AtomicNodeRunning(computeService);
AtomicReference<NodeMetadata> reference = new AtomicReference<NodeMetadata>(pending);
Assert.assertTrue(nodeRunning.apply(reference));
Assert.assertEquals(reference.get(), running);
verify(computeService);
}
@BeforeMethod
public void setUp() throws Exception {
node = createMock(NodeMetadata.class);
computeService = createMock(GetNodeMetadataStrategy.class);
expect(node.getId()).andReturn("myid").anyTimes();
expect(computeService.getNode("myid")).andReturn(node).anyTimes();
expect(node.getLocation()).andReturn(null).anyTimes();
}
@Test
public void testNodeRunningReturnsTrueWhenRunning() {
expect(node.getState()).andReturn(NodeState.RUNNING).atLeastOnce();
replay(node);
replay(computeService);
AtomicNodeRunning nodeRunning = new AtomicNodeRunning(computeService);
AtomicReference<NodeMetadata> reference = new AtomicReference<NodeMetadata>(node);
Assert.assertTrue(nodeRunning.apply(reference));
Assert.assertEquals(reference.get(), node);
}
@Test(expectedExceptions = IllegalStateException.class)
public void testNodeRunningFailsOnTerminated() {
expect(node.getState()).andReturn(NodeState.TERMINATED).atLeastOnce();
replay(node);
replay(computeService);
AtomicNodeRunning nodeRunning = new AtomicNodeRunning(computeService);
AtomicReference<NodeMetadata> reference = new AtomicReference<NodeMetadata>(node);
nodeRunning.apply(reference);
Assert.assertEquals(reference.get(), node);
}
@Test(expectedExceptions = IllegalStateException.class)
public void testNodeRunningFailsOnError() {
expect(node.getState()).andReturn(NodeState.ERROR).atLeastOnce();
replay(node);
replay(computeService);
AtomicNodeRunning nodeRunning = new AtomicNodeRunning(computeService);
AtomicReference<NodeMetadata> reference = new AtomicReference<NodeMetadata>(node);
nodeRunning.apply(reference);
Assert.assertEquals(reference.get(), node);
}
}

View File

@ -18,14 +18,14 @@
*/ */
package org.jclouds.compute.strategy; package org.jclouds.compute.strategy;
import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.createMock; import static org.easymock.EasyMock.replay;
import static org.easymock.classextension.EasyMock.replay; import static org.easymock.EasyMock.verify;
import static org.easymock.classextension.EasyMock.verify;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import org.jclouds.compute.config.CustomizationResponse; import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
@ -33,13 +33,14 @@ import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.NodeState; import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.functions.TemplateOptionsToStatement; import org.jclouds.compute.functions.TemplateOptionsToStatement;
import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.predicates.AtomicNodeRunning;
import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen; import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen;
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
import org.testng.Assert;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
@ -52,11 +53,8 @@ import com.google.common.collect.Sets;
@Test(groups = "unit") @Test(groups = "unit")
public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest { public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest {
@SuppressWarnings("unchecked")
public void testBreakWhenNodeStillPending() { public void testBreakWhenNodeStillPending() {
Predicate<NodeMetadata> nodeRunning = createMock(Predicate.class);
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory = createMock(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class); InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory = createMock(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class);
GetNodeMetadataStrategy getNode = createMock(GetNodeMetadataStrategy.class);
RetryIfSocketNotYetOpen socketTester = createMock(RetryIfSocketNotYetOpen.class); RetryIfSocketNotYetOpen socketTester = createMock(RetryIfSocketNotYetOpen.class);
Timeouts timeouts = new Timeouts(); Timeouts timeouts = new Timeouts();
Function<TemplateOptions, Statement> templateOptionsToStatement = new TemplateOptionsToStatement(); Function<TemplateOptions, Statement> templateOptionsToStatement = new TemplateOptionsToStatement();
@ -67,41 +65,39 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest {
Map<NodeMetadata, Exception> badNodes = Maps.newLinkedHashMap(); Map<NodeMetadata, Exception> badNodes = Maps.newLinkedHashMap();
Multimap<NodeMetadata, CustomizationResponse> customizationResponses = LinkedHashMultimap.create(); Multimap<NodeMetadata, CustomizationResponse> customizationResponses = LinkedHashMultimap.create();
NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.PENDING).build(); final NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.PENDING).build();
// node never reached running state // node always stays pending
expect(nodeRunning.apply(node)).andReturn(false); GetNodeMetadataStrategy nodeRunning = new GetNodeMetadataStrategy(){
expect(getNode.getNode(node.getId())).andReturn(node);
@Override
public NodeMetadata getNode(String input) {
Assert.assertEquals(input, node.getId());
return node;
}
};
// replay mocks // replay mocks
replay(nodeRunning); replay(initScriptRunnerFactory, socketTester);
replay(initScriptRunnerFactory);
replay(getNode);
replay(socketTester);
// run // run
new CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(nodeRunning, getNode, socketTester, timeouts, AtomicReference<NodeMetadata> atomicNode = new AtomicReference<NodeMetadata>(node);
templateOptionsToStatement, initScriptRunnerFactory, options, node, goodNodes, badNodes, new CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap( new AtomicNodeRunning(nodeRunning), socketTester, timeouts,
customizationResponses).apply(node); templateOptionsToStatement, initScriptRunnerFactory, options, atomicNode, goodNodes, badNodes,
customizationResponses).apply(atomicNode);
assertEquals(goodNodes.size(), 0); assertEquals(goodNodes.size(), 0);
assertEquals(badNodes.keySet(), ImmutableSet.of(node)); assertEquals(badNodes.keySet(), ImmutableSet.of(node));
assertEquals(badNodes.get(node).getMessage(), assertEquals(badNodes.get(node).getMessage(),
"node(id) didn't achieve the state running within 1200 seconds, final state: PENDING"); "node(id) didn't achieve the state running within 1200 seconds, so we couldn't customize; final state: PENDING");
assertEquals(customizationResponses.size(), 0); assertEquals(customizationResponses.size(), 0);
// verify mocks // verify mocks
verify(nodeRunning); verify(initScriptRunnerFactory, socketTester);
verify(initScriptRunnerFactory);
verify(getNode);
verify(socketTester);
} }
@SuppressWarnings("unchecked")
public void testBreakGraceFullyWhenNodeDied() { public void testBreakGraceFullyWhenNodeDied() {
Predicate<NodeMetadata> nodeRunning = createMock(Predicate.class);
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory = createMock(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class); InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory = createMock(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class);
GetNodeMetadataStrategy getNode = createMock(GetNodeMetadataStrategy.class);
RetryIfSocketNotYetOpen socketTester = createMock(RetryIfSocketNotYetOpen.class); RetryIfSocketNotYetOpen socketTester = createMock(RetryIfSocketNotYetOpen.class);
Timeouts timeouts = new Timeouts(); Timeouts timeouts = new Timeouts();
Function<TemplateOptions, Statement> templateOptionsToStatement = new TemplateOptionsToStatement(); Function<TemplateOptions, Statement> templateOptionsToStatement = new TemplateOptionsToStatement();
@ -112,32 +108,35 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest {
Map<NodeMetadata, Exception> badNodes = Maps.newLinkedHashMap(); Map<NodeMetadata, Exception> badNodes = Maps.newLinkedHashMap();
Multimap<NodeMetadata, CustomizationResponse> customizationResponses = LinkedHashMultimap.create(); Multimap<NodeMetadata, CustomizationResponse> customizationResponses = LinkedHashMultimap.create();
NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.PENDING).build(); final NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.PENDING).build();
final NodeMetadata deadNnode = new NodeMetadataBuilder().ids("id").state(NodeState.TERMINATED).build();
// node never reached running state // node dies
expect(nodeRunning.apply(node)).andReturn(false); GetNodeMetadataStrategy nodeRunning = new GetNodeMetadataStrategy(){
expect(getNode.getNode(node.getId())).andReturn(null);
@Override
public NodeMetadata getNode(String input) {
Assert.assertEquals(input, node.getId());
return deadNnode;
}
};
// replay mocks // replay mocks
replay(nodeRunning); replay(initScriptRunnerFactory, socketTester);
replay(initScriptRunnerFactory);
replay(getNode);
replay(socketTester);
// run // run
new CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(nodeRunning, getNode, socketTester, timeouts, AtomicReference<NodeMetadata> atomicNode = new AtomicReference<NodeMetadata>(node);
templateOptionsToStatement, initScriptRunnerFactory, options, node, goodNodes, badNodes, new CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap( new AtomicNodeRunning(nodeRunning), socketTester, timeouts,
customizationResponses).apply(node); templateOptionsToStatement, initScriptRunnerFactory, options, atomicNode, goodNodes, badNodes,
customizationResponses).apply(atomicNode);
assertEquals(goodNodes.size(), 0); assertEquals(goodNodes.size(), 0);
assertEquals(badNodes.keySet(), ImmutableSet.of(node)); assertEquals(badNodes.keySet(), ImmutableSet.of(node));
badNodes.get(node).printStackTrace();
assertEquals(badNodes.get(node).getMessage(), "node(id) terminated before we could customize"); assertEquals(badNodes.get(node).getMessage(), "node(id) terminated before we could customize");
assertEquals(customizationResponses.size(), 0); assertEquals(customizationResponses.size(), 0);
// verify mocks // verify mocks
verify(nodeRunning); verify(initScriptRunnerFactory, socketTester);
verify(initScriptRunnerFactory);
verify(getNode);
verify(socketTester);
} }
} }

View File

@ -25,9 +25,9 @@ import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_GENERAT
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@ -100,9 +100,9 @@ public class AWSEC2ComputeService extends EC2ComputeService {
DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy startNodeStrategy, DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy startNodeStrategy,
SuspendNodeStrategy stopNodeStrategy, Provider<TemplateBuilder> templateBuilderProvider, SuspendNodeStrategy stopNodeStrategy, Provider<TemplateBuilder> templateBuilderProvider,
Provider<TemplateOptions> templateOptionsProvider, Provider<TemplateOptions> templateOptionsProvider,
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning, @Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning,
@Named("NODE_TERMINATED") Predicate<NodeMetadata> nodeTerminated, @Named("NODE_TERMINATED") Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
@Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended, @Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,

View File

@ -23,6 +23,7 @@ import static com.google.common.collect.Iterables.transform;
import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_GENERATE_INSTANCE_NAMES; import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_GENERATE_INSTANCE_NAMES;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
@ -79,7 +80,7 @@ public class AWSEC2CreateNodesInGroupThenAddToSet extends EC2CreateNodesInGroupT
protected AWSEC2CreateNodesInGroupThenAddToSet( protected AWSEC2CreateNodesInGroupThenAddToSet(
AWSEC2Client client, AWSEC2Client client,
@Named("ELASTICIP") LoadingCache<RegionAndName, String> elasticIpCache, @Named("ELASTICIP") LoadingCache<RegionAndName, String> elasticIpCache,
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning, @Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning,
AWSEC2AsyncClient aclient, AWSEC2AsyncClient aclient,
@Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean generateInstanceNames, @Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean generateInstanceNames,
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateBuilder> templateBuilderProvider,

View File

@ -21,6 +21,7 @@ package org.jclouds.gogrid.compute;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@ -68,9 +69,9 @@ public class GoGridComputeService extends BaseComputeService {
RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy, RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy,
ResumeNodeStrategy resumeNodeStrategy, SuspendNodeStrategy suspendNodeStrategy, ResumeNodeStrategy resumeNodeStrategy, SuspendNodeStrategy suspendNodeStrategy,
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider, Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateOptions> templateOptionsProvider,
@Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning, @Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning,
@Named("NODE_TERMINATED") Predicate<NodeMetadata> nodeTerminated, @Named("NODE_TERMINATED") Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
@Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended, @Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess,
RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) { @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {