Issue 612: added Name support to aws-ec2

This commit is contained in:
Adrian Cole 2011-10-15 00:26:54 -07:00
parent b85b861d8b
commit ed47d255b0
8 changed files with 117 additions and 71 deletions

View File

@ -150,11 +150,11 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
String zone = getZoneFromLocationOrNull(template.getLocation());
RunInstancesOptions instanceOptions = createKeyPairAndSecurityGroupsAsNeededAndReturncustomize.execute(region,
group, template);
return createNodesInRegionAndZone(region, zone, count, template, instanceOptions);
return createNodesInRegionAndZone(region, zone, group, count, template, instanceOptions);
}
protected Iterable<? extends RunningInstance> createNodesInRegionAndZone(String region, String zone, int count,
Template template, RunInstancesOptions instanceOptions) {
protected Iterable<? extends RunningInstance> createNodesInRegionAndZone(String region, String zone, String group,
int count, Template template, RunInstancesOptions instanceOptions) {
int countStarted = 0;
int tries = 0;
Iterable<? extends RunningInstance> started = ImmutableSet.<RunningInstance> of();

View File

@ -23,6 +23,7 @@ import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_AMI_QUE
import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_CC_AMI_QUERY;
import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_CC_AMIs;
import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_CC_REGIONS;
import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_GENERATE_INSTANCE_NAMES;
import static org.jclouds.compute.reference.ComputeServiceConstants.PROPERTY_TIMEOUT_NODE_SUSPENDED;
import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_AMI_OWNERS;
@ -49,6 +50,7 @@ public class AWSEC2PropertiesBuilder extends org.jclouds.ec2.EC2PropertiesBuilde
properties.setProperty("jclouds.ssh.max-retries", "7");
properties.setProperty("jclouds.ssh.retry-auth", "true");
properties.setProperty(PROPERTY_ENDPOINT, "https://ec2.us-east-1.amazonaws.com");
properties.setProperty(PROPERTY_EC2_GENERATE_INSTANCE_NAMES, "true");
properties.putAll(Region.regionProperties());
properties.remove(PROPERTY_EC2_AMI_OWNERS);
// amazon, alestic, canonical, and rightscale

View File

@ -18,8 +18,10 @@
*/
package org.jclouds.aws.ec2.compute;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.transform;
import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_GENERATE_INSTANCE_NAMES;
import java.util.Map;
import java.util.Set;
@ -33,6 +35,7 @@ import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.aws.ec2.AWSEC2AsyncClient;
import org.jclouds.aws.ec2.AWSEC2Client;
import org.jclouds.aws.ec2.domain.PlacementGroup;
import org.jclouds.aws.ec2.domain.PlacementGroup.State;
@ -72,6 +75,7 @@ import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.cache.Cache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
@ -84,74 +88,90 @@ public class AWSEC2ComputeService extends EC2ComputeService {
private final Cache<RegionAndName, String> placementGroupMap;
private final Predicate<PlacementGroup> placementGroupDeleted;
private final AWSEC2Client ec2Client;
private final AWSEC2AsyncClient aclient;
private final boolean generateInstanceNames;
@Inject
protected AWSEC2ComputeService(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, CreateNodesInGroupThenAddToSet 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,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, AWSEC2Client ec2Client,
ConcurrentMap<RegionAndName, KeyPair> credentialsMap,
@Named("SECURITY") Cache<RegionAndName, String> securityGroupMap,
@Named("PLACEMENT") Cache<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,
CreateNodesInGroupThenAddToSet 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,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, AWSEC2Client ec2Client,
ConcurrentMap<RegionAndName, KeyPair> credentialsMap,
@Named("SECURITY") Cache<RegionAndName, String> securityGroupMap,
@Named("PLACEMENT") Cache<RegionAndName, String> placementGroupMap,
@Named("DELETED") Predicate<PlacementGroup> placementGroupDeleted,
@Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean generateInstanceNames, AWSEC2AsyncClient aclient) {
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, stopNodeStrategy,
templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, nodeSuspended,
initScriptRunnerFactory, runScriptOnNodeFactory, initAdminAccess, persistNodeCredentials, timeouts,
executor, ec2Client, credentialsMap, securityGroupMap);
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy,
stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
nodeSuspended, initScriptRunnerFactory, runScriptOnNodeFactory, initAdminAccess, persistNodeCredentials,
timeouts, executor, ec2Client, credentialsMap, securityGroupMap);
this.ec2Client = ec2Client;
this.placementGroupMap = placementGroupMap;
this.placementGroupDeleted = placementGroupDeleted;
this.generateInstanceNames = generateInstanceNames;
this.aclient = checkNotNull(aclient, "aclient");
}
@Override
public Set<? extends NodeMetadata> createNodesInGroup(String group, int count, final Template template)
throws RunNodesException {
throws RunNodesException {
Set<? extends NodeMetadata> nodes = super.createNodesInGroup(group, count, template);
// tags from spot requests do not propagate to running instances
// automatically
if (templateWasASpotRequestWithUserMetadata(template)) {
addTagsToNodesFromUserMetadataInTemplate(nodes, template);
nodes = addUserMetadataFromTemplateOptionsToNodes(template, nodes);
addTagsToNodesFromUserMetadataInTemplate(nodes, group, template);
nodes = addUserMetadataFromTemplateOptionsToNodes(template, group, nodes);
}
return nodes;
}
protected void addTagsToNodesFromUserMetadataInTemplate(Set<? extends NodeMetadata> nodes, final Template template) {
protected void addTagsToNodesFromUserMetadataInTemplate(Set<? extends NodeMetadata> nodes, String group,
final Template template) {
String region = AWSUtils.getRegionFromLocationOrNull(template.getLocation());
ec2Client.getTagServices().createTagsInRegion(region, transform(nodes, new Function<NodeMetadata, String>() {
if (template.getOptions().getUserMetadata().size() > 0 || generateInstanceNames) {
for (String id : transform(nodes, new Function<NodeMetadata, String>() {
@Override
public String apply(NodeMetadata arg0) {
return arg0.getProviderId();
}
@Override
public String apply(NodeMetadata arg0) {
return arg0.getProviderId();
}
}), template.getOptions().getUserMetadata());
}))
aclient.getTagServices().createTagsInRegion(region, ImmutableSet.of(id),
metadataForId(id, group, template.getOptions().getUserMetadata()));
}
}
private Map<String, String> metadataForId(String id, String group, Map<String, String> metadata) {
return generateInstanceNames && !metadata.containsKey("Name") ? ImmutableMap.<String, String> builder().putAll(
metadata).put("Name", id.replaceAll(".*-", group + "-")).build() : metadata;
}
protected boolean templateWasASpotRequestWithUserMetadata(final Template template) {
return template.getOptions().getUserMetadata().size() > 0
&& AWSEC2TemplateOptions.class.cast(template.getOptions()).getSpotPrice() != null;
&& AWSEC2TemplateOptions.class.cast(template.getOptions()).getSpotPrice() != null;
}
protected Set<? extends NodeMetadata> addUserMetadataFromTemplateOptionsToNodes(final Template template,
Set<? extends NodeMetadata> nodes) {
final String group, Set<? extends NodeMetadata> nodes) {
nodes = ImmutableSet.copyOf(Iterables.transform(nodes, new Function<NodeMetadata, NodeMetadata>() {
@Override
public NodeMetadata apply(NodeMetadata arg0) {
return NodeMetadataBuilder.fromNodeMetadata(arg0).userMetadata(template.getOptions().getUserMetadata())
.build();
Map<String, String> md = metadataForId(arg0.getProviderId(), group, template.getOptions().getUserMetadata());
return NodeMetadataBuilder.fromNodeMetadata(arg0).name(md.get("Name")).userMetadata(md).build();
}
}));
@ -169,9 +189,9 @@ public class AWSEC2ComputeService extends EC2ComputeService {
logger.debug(">> deleting placementGroup(%s)", placementGroup);
try {
ec2Client.getPlacementGroupServices().deletePlacementGroupInRegion(region, placementGroup);
checkState(
placementGroupDeleted.apply(new PlacementGroup(region, placementGroup, "cluster", State.PENDING)),
String.format("placementGroup region(%s) name(%s) failed to delete", region, placementGroup));
checkState(placementGroupDeleted.apply(new PlacementGroup(region, placementGroup, "cluster",
State.PENDING)), String.format("placementGroup region(%s) name(%s) failed to delete", region,
placementGroup));
placementGroupMap.invalidate(new RegionAndName(region, placementGroup));
logger.debug("<< deleted placementGroup(%s)", placementGroup);
} catch (IllegalStateException e) {

View File

@ -72,8 +72,7 @@ public class AWSRunningInstanceToNodeMetadata extends RunningInstanceToNodeMetad
@Override
protected NodeMetadataBuilder buildInstance(RunningInstance instance, NodeMetadataBuilder builder) {
Map<String, String> tags = AWSRunningInstance.class.cast(instance).getTags();
return super.buildInstance(instance, builder)
.tags(filterValues(tags, equalTo("")).keySet())
.userMetadata(filterValues(tags, not(equalTo(""))));
return super.buildInstance(instance, builder).name(tags.get("Name")).tags(
filterValues(tags, equalTo("")).keySet()).userMetadata(filterValues(tags, not(equalTo(""))));
}
}

View File

@ -20,6 +20,7 @@ package org.jclouds.aws.ec2.compute.strategy;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.transform;
import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_GENERATE_INSTANCE_NAMES;
import java.util.Map;
@ -29,6 +30,7 @@ import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.aws.ec2.AWSEC2AsyncClient;
import org.jclouds.aws.ec2.AWSEC2Client;
import org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions;
import org.jclouds.aws.ec2.compute.predicates.AWSEC2InstancePresent;
@ -51,6 +53,8 @@ import org.jclouds.logging.Logger;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.cache.Cache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
/**
*
@ -66,60 +70,72 @@ public class AWSEC2CreateNodesInGroupThenAddToSet extends EC2CreateNodesInGroupT
@VisibleForTesting
final AWSEC2Client client;
final SpotInstanceRequestToAWSRunningInstance spotConverter;
final AWSEC2AsyncClient aclient;
final boolean generateInstanceNames;
@Inject
protected AWSEC2CreateNodesInGroupThenAddToSet(
AWSEC2Client client,
Provider<TemplateBuilder> templateBuilderProvider,
CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
AWSEC2InstancePresent instancePresent, Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
Cache<RunningInstance, Credentials> instanceToCredentials, Map<String, Credentials> credentialStore,
ComputeUtils utils, SpotInstanceRequestToAWSRunningInstance spotConverter) {
AWSEC2Client client,
AWSEC2AsyncClient aclient,
@Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean generateInstanceNames,
Provider<TemplateBuilder> templateBuilderProvider,
CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
AWSEC2InstancePresent instancePresent,
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
Cache<RunningInstance, Credentials> instanceToCredentials, Map<String, Credentials> credentialStore,
ComputeUtils utils, SpotInstanceRequestToAWSRunningInstance spotConverter) {
super(client, templateBuilderProvider, createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, instancePresent,
runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils);
runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils);
this.client = checkNotNull(client, "client");
this.aclient = checkNotNull(aclient, "aclient");
this.spotConverter = checkNotNull(spotConverter, "spotConverter");
this.generateInstanceNames = generateInstanceNames;
}
protected Iterable<? extends RunningInstance> createNodesInRegionAndZone(String region, String zone, int count,
Template template, RunInstancesOptions instanceOptions) {
@Override
protected Iterable<? extends RunningInstance> createNodesInRegionAndZone(String region, String zone, String group,
int count, Template template, RunInstancesOptions instanceOptions) {
Float spotPrice = getSpotPriceOrNull(template.getOptions());
if (spotPrice != null) {
LaunchSpecification spec = AWSRunInstancesOptions.class.cast(instanceOptions).getLaunchSpecificationBuilder()
.imageId(template.getImage().getProviderId()).availabilityZone(zone).build();
.imageId(template.getImage().getProviderId()).availabilityZone(zone).build();
RequestSpotInstancesOptions options = AWSEC2TemplateOptions.class.cast(template.getOptions()).getSpotOptions();
if (logger.isDebugEnabled())
logger.debug(">> requesting %d spot instances region(%s) price(%f) spec(%s) options(%s)", count, region,
spotPrice, spec, options);
spotPrice, spec, options);
return addTagsToInstancesInRegion(
template.getOptions().getUserMetadata(),
transform(
client.getSpotInstanceServices().requestSpotInstancesInRegion(region, spotPrice, count, spec,
options), spotConverter), region);
return addTagsToInstancesInRegion(template.getOptions().getUserMetadata(), transform(client
.getSpotInstanceServices().requestSpotInstancesInRegion(region, spotPrice, count, spec, options),
spotConverter), region, group);
} else {
return addTagsToInstancesInRegion(template.getOptions().getUserMetadata(),
super.createNodesInRegionAndZone(region, zone, count, template, instanceOptions), region);
return addTagsToInstancesInRegion(template.getOptions().getUserMetadata(), super.createNodesInRegionAndZone(
region, zone, group, count, template, instanceOptions), region, group);
}
}
public Iterable<? extends RunningInstance> addTagsToInstancesInRegion(Map<String, String> metadata,
Iterable<? extends RunningInstance> iterable, String region) {
if (metadata.size() > 0) {
client.getTagServices().createTagsInRegion(region,
transform(iterable, new Function<RunningInstance, String>() {
Iterable<? extends RunningInstance> iterable, String region, String group) {
if (metadata.size() > 0 || generateInstanceNames) {
for (String id : transform(iterable, new Function<RunningInstance, String>() {
@Override
public String apply(RunningInstance arg0) {
return arg0.getId();
}
@Override
public String apply(RunningInstance arg0) {
return arg0.getId();
}
}), metadata);
}))
aclient.getTagServices()
.createTagsInRegion(region, ImmutableSet.of(id), metadataForId(id, group, metadata));
}
return iterable;
}
private Map<String, String> metadataForId(String id, String group, Map<String, String> metadata) {
return generateInstanceNames && !metadata.containsKey("Name") ? ImmutableMap.<String, String> builder().putAll(
metadata).put("Name", id.replaceAll(".*-", group + "-")).build() : metadata;
}
private Float getSpotPriceOrNull(TemplateOptions options) {
return options instanceof AWSEC2TemplateOptions ? AWSEC2TemplateOptions.class.cast(options).getSpotPrice() : null;
}

View File

@ -46,5 +46,10 @@ public interface AWSEC2Constants extends EC2Constants {
public static final String PROPERTY_EC2_CC_AMI_QUERY = "jclouds.ec2.cc-ami-query";
public static final String PROPERTY_EC2_CC_REGIONS = "jclouds.ec2.cc-regions";
public static final String PROPERTY_EC2_AMI_QUERY = "jclouds.ec2.ami-query";
/**
* If this property is set to true(default), jclouds generate a name for each instance based on
* the group. ex. i-ef34ae2 becomes hadoop-ef34ae2.
*/
public static final String PROPERTY_EC2_GENERATE_INSTANCE_NAMES = "jclouds.ec2.generate-instance-names";
}

View File

@ -133,6 +133,9 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
Set<? extends NodeMetadata> nodes = client.createNodesInGroup(group, 1, template);
NodeMetadata first = Iterables.get(nodes, 0);
//Name metadata should turn into node.name
assertEquals(first.getName(), group);
checkUserMetadataInNodeEquals(first, userMetadata);
assert first.getCredentials() != null : first;

View File

@ -131,6 +131,7 @@ public class AWSRunningInstanceToNodeMetadataTest {
new NodeMetadataBuilder()
.state(NodeState.RUNNING)
.group("zkclustertest")
.name("foo")
.hostname("ip-10-212-81-7")
.privateAddresses(ImmutableSet.of("10.212.81.7"))
.publicAddresses(ImmutableSet.of("174.129.173.155"))