mirror of https://github.com/apache/jclouds.git
Issue 308: added compute service hooks for spot instances
This commit is contained in:
parent
af0cff189c
commit
b0c4b9be9a
|
@ -25,7 +25,6 @@ import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_AMI_OWNERS;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
@ -54,13 +53,10 @@ import org.jclouds.ec2.compute.options.EC2TemplateOptions;
|
||||||
import org.jclouds.ec2.domain.InstanceState;
|
import org.jclouds.ec2.domain.InstanceState;
|
||||||
import org.jclouds.ec2.domain.KeyPair;
|
import org.jclouds.ec2.domain.KeyPair;
|
||||||
import org.jclouds.ec2.domain.RunningInstance;
|
import org.jclouds.ec2.domain.RunningInstance;
|
||||||
import org.jclouds.ec2.predicates.InstancePresent;
|
|
||||||
import org.jclouds.predicates.RetryablePredicate;
|
|
||||||
import org.jclouds.rest.RestContext;
|
import org.jclouds.rest.RestContext;
|
||||||
import org.jclouds.rest.internal.RestContextImpl;
|
import org.jclouds.rest.internal.RestContextImpl;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.base.Predicate;
|
|
||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Splitter;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
@ -77,9 +73,9 @@ import com.google.inject.TypeLiteral;
|
||||||
public class EC2ComputeServiceDependenciesModule extends AbstractModule {
|
public class EC2ComputeServiceDependenciesModule extends AbstractModule {
|
||||||
|
|
||||||
public static final Map<InstanceState, NodeState> instanceToNodeState = ImmutableMap
|
public static final Map<InstanceState, NodeState> instanceToNodeState = ImmutableMap
|
||||||
.<InstanceState, NodeState> builder().put(InstanceState.PENDING, NodeState.PENDING)
|
.<InstanceState, NodeState> builder().put(InstanceState.PENDING, NodeState.PENDING).put(
|
||||||
.put(InstanceState.RUNNING, NodeState.RUNNING).put(InstanceState.SHUTTING_DOWN, NodeState.PENDING)
|
InstanceState.RUNNING, NodeState.RUNNING).put(InstanceState.SHUTTING_DOWN, NodeState.PENDING).put(
|
||||||
.put(InstanceState.TERMINATED, NodeState.TERMINATED).put(InstanceState.STOPPING, NodeState.PENDING)
|
InstanceState.TERMINATED, NodeState.TERMINATED).put(InstanceState.STOPPING, NodeState.PENDING)
|
||||||
.put(InstanceState.STOPPED, NodeState.SUSPENDED).put(InstanceState.UNRECOGNIZED, NodeState.UNRECOGNIZED)
|
.put(InstanceState.STOPPED, NodeState.SUSPENDED).put(InstanceState.UNRECOGNIZED, NodeState.UNRECOGNIZED)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -89,13 +85,6 @@ public class EC2ComputeServiceDependenciesModule extends AbstractModule {
|
||||||
return instanceToNodeState;
|
return instanceToNodeState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
@Named("PRESENT")
|
|
||||||
protected Predicate<RunningInstance> instancePresent(InstancePresent present) {
|
|
||||||
return new RetryablePredicate<RunningInstance>(present, 5000, 200, TimeUnit.MILLISECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
bind(TemplateBuilder.class).to(EC2TemplateBuilderImpl.class);
|
bind(TemplateBuilder.class).to(EC2TemplateBuilderImpl.class);
|
||||||
|
|
|
@ -73,7 +73,7 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
|
||||||
protected final Map<InstanceState, NodeState> instanceToNodeState;
|
protected final Map<InstanceState, NodeState> instanceToNodeState;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
RunningInstanceToNodeMetadata(Map<InstanceState, NodeState> instanceToNodeState,
|
protected RunningInstanceToNodeMetadata(Map<InstanceState, NodeState> instanceToNodeState,
|
||||||
Map<String, Credentials> credentialStore, Map<RegionAndName, Image> instanceToImage,
|
Map<String, Credentials> credentialStore, Map<RegionAndName, Image> instanceToImage,
|
||||||
@Memoized Supplier<Set<? extends Location>> locations, @Memoized Supplier<Set<? extends Hardware>> hardware) {
|
@Memoized Supplier<Set<? extends Location>> locations, @Memoized Supplier<Set<? extends Hardware>> hardware) {
|
||||||
this.locations = checkNotNull(locations, "locations");
|
this.locations = checkNotNull(locations, "locations");
|
||||||
|
@ -85,13 +85,14 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NodeMetadata apply(RunningInstance instance) {
|
public NodeMetadata apply(RunningInstance instance) {
|
||||||
|
if (instance == null || instance.getId() == null)
|
||||||
|
return null;
|
||||||
NodeMetadataBuilder builder = new NodeMetadataBuilder();
|
NodeMetadataBuilder builder = new NodeMetadataBuilder();
|
||||||
String providerId = checkNotNull(instance, "instance").getId();
|
builder.providerId(instance.getId());
|
||||||
builder.providerId(providerId);
|
builder.id(instance.getRegion() + "/" + instance.getId());
|
||||||
builder.id(instance.getRegion() + "/" + providerId);
|
|
||||||
String group = getGroupForInstance(instance);
|
String group = getGroupForInstance(instance);
|
||||||
builder.group(group);
|
builder.group(group);
|
||||||
builder.credentials(credentialStore.get("node#" + instance.getRegion() + "/" + providerId));
|
addCredentialsForInstance(builder, instance);
|
||||||
builder.state(instanceToNodeState.get(instance.getInstanceState()));
|
builder.state(instanceToNodeState.get(instance.getInstanceState()));
|
||||||
builder.publicAddresses(NullSafeCollections.nullSafeSet(instance.getIpAddress()));
|
builder.publicAddresses(NullSafeCollections.nullSafeSet(instance.getIpAddress()));
|
||||||
builder.privateAddresses(NullSafeCollections.nullSafeSet(instance.getPrivateIpAddress()));
|
builder.privateAddresses(NullSafeCollections.nullSafeSet(instance.getPrivateIpAddress()));
|
||||||
|
@ -106,9 +107,9 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
|
||||||
Image image = instanceToImage.get(regionAndName);
|
Image image = instanceToImage.get(regionAndName);
|
||||||
if (image != null)
|
if (image != null)
|
||||||
builder.operatingSystem(image.getOperatingSystem());
|
builder.operatingSystem(image.getOperatingSystem());
|
||||||
}
|
} catch (NullPointerException e) {
|
||||||
catch (NullPointerException e) {
|
// The instanceToImage Map may throw NullPointerException (actually subclass
|
||||||
// The instanceToImage Map may throw NullPointerException (actually subclass NullOutputException) if the
|
// NullOutputException) if the
|
||||||
// computing Function returns a null value.
|
// computing Function returns a null value.
|
||||||
//
|
//
|
||||||
// See the following for more information:
|
// See the following for more information:
|
||||||
|
@ -119,6 +120,10 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void addCredentialsForInstance(NodeMetadataBuilder builder, RunningInstance instance) {
|
||||||
|
builder.credentials(credentialStore.get("node#" + instance.getRegion() + "/" + instance.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
protected Hardware parseHardware(final RunningInstance instance) {
|
protected Hardware parseHardware(final RunningInstance instance) {
|
||||||
Hardware hardware = getHardwareForInstance(instance);
|
Hardware hardware = getHardwareForInstance(instance);
|
||||||
|
|
||||||
|
@ -171,8 +176,7 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
|
||||||
} catch (NoSuchElementException e) {
|
} catch (NoSuchElementException e) {
|
||||||
logger.debug("no group parsed from %s's security groups: %s", instance.getId(), instance.getGroupIds());
|
logger.debug("no group parsed from %s's security groups: %s", instance.getId(), instance.getGroupIds());
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
logger
|
logger.debug("too many groups match %s; %s's security groups: %s", "jclouds#", instance.getId(), instance
|
||||||
.debug("too many groups match %s; %s's security groups: %s", "jclouds#", instance.getId(), instance
|
|
||||||
.getGroupIds());
|
.getGroupIds());
|
||||||
}
|
}
|
||||||
return group;
|
return group;
|
||||||
|
@ -203,6 +207,8 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
|
||||||
}
|
}
|
||||||
|
|
||||||
private Location findLocationWithId(final String locationId) {
|
private Location findLocationWithId(final String locationId) {
|
||||||
|
if (locationId == null)
|
||||||
|
return null;
|
||||||
try {
|
try {
|
||||||
Location location = Iterables.find(locations.get(), new Predicate<Location>() {
|
Location location = Iterables.find(locations.get(), new Predicate<Location>() {
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,9 @@
|
||||||
* ====================================================================
|
* ====================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jclouds.ec2.predicates;
|
package org.jclouds.ec2.compute.predicates;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
|
@ -25,7 +27,7 @@ import javax.annotation.Resource;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import org.jclouds.ec2.EC2Client;
|
import org.jclouds.ec2.EC2Client;
|
||||||
import org.jclouds.ec2.domain.RunningInstance;
|
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||||
import org.jclouds.logging.Logger;
|
import org.jclouds.logging.Logger;
|
||||||
import org.jclouds.rest.ResourceNotFoundException;
|
import org.jclouds.rest.ResourceNotFoundException;
|
||||||
|
|
||||||
|
@ -34,13 +36,11 @@ import com.google.common.collect.Iterables;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* Tests to see if a task succeeds.
|
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
@Singleton
|
@Singleton
|
||||||
public class InstancePresent implements Predicate<RunningInstance> {
|
public class InstancePresent implements Predicate<RegionAndName> {
|
||||||
|
|
||||||
private final EC2Client client;
|
private final EC2Client client;
|
||||||
|
|
||||||
|
@ -49,13 +49,13 @@ public class InstancePresent implements Predicate<RunningInstance> {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public InstancePresent(EC2Client client) {
|
public InstancePresent(EC2Client client) {
|
||||||
this.client = client;
|
this.client = checkNotNull(client, "client");
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean apply(RunningInstance instance) {
|
public boolean apply(RegionAndName instance) {
|
||||||
logger.trace("looking for instance %s", instance);
|
logger.trace("looking for instance %s/%s", instance.getRegion(), instance.getName());
|
||||||
try {
|
try {
|
||||||
instance = refresh(instance);
|
refresh(instance);
|
||||||
return true;
|
return true;
|
||||||
} catch (ResourceNotFoundException e) {
|
} catch (ResourceNotFoundException e) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -64,8 +64,8 @@ public class InstancePresent implements Predicate<RunningInstance> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private RunningInstance refresh(RunningInstance instance) {
|
protected void refresh(RegionAndName instance) {
|
||||||
return Iterables.getOnlyElement(Iterables.getOnlyElement(client.getInstanceServices().describeInstancesInRegion(
|
Iterables.getOnlyElement(Iterables.getOnlyElement(client.getInstanceServices().describeInstancesInRegion(
|
||||||
instance.getRegion(), instance.getId())));
|
instance.getRegion(), instance.getName())));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,10 +19,10 @@
|
||||||
|
|
||||||
package org.jclouds.ec2.compute.strategy;
|
package org.jclouds.ec2.compute.strategy;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static com.google.common.collect.Iterables.all;
|
import static com.google.common.collect.Iterables.all;
|
||||||
import static com.google.common.collect.Iterables.transform;
|
import static com.google.common.collect.Iterables.transform;
|
||||||
import static org.jclouds.ec2.compute.util.EC2ComputeUtils.getZoneFromLocationOrNull;
|
import static org.jclouds.ec2.compute.util.EC2ComputeUtils.getZoneFromLocationOrNull;
|
||||||
import static org.jclouds.ec2.compute.util.EC2ComputeUtils.instanceToId;
|
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -44,6 +44,8 @@ import org.jclouds.compute.strategy.CreateNodesInGroupThenAddToSet;
|
||||||
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.ec2.EC2Client;
|
import org.jclouds.ec2.EC2Client;
|
||||||
|
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||||
|
import org.jclouds.ec2.compute.predicates.InstancePresent;
|
||||||
import org.jclouds.ec2.domain.RunningInstance;
|
import org.jclouds.ec2.domain.RunningInstance;
|
||||||
import org.jclouds.ec2.options.RunInstancesOptions;
|
import org.jclouds.ec2.options.RunInstancesOptions;
|
||||||
import org.jclouds.logging.Logger;
|
import org.jclouds.logging.Logger;
|
||||||
|
@ -51,7 +53,6 @@ import org.jclouds.logging.Logger;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
import com.google.common.base.Predicate;
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
|
@ -76,30 +77,38 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
|
||||||
final Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata;
|
final Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
final ComputeUtils utils;
|
final ComputeUtils utils;
|
||||||
final Predicate<RunningInstance> instancePresent;
|
final InstancePresent instancePresent;
|
||||||
final Function<RunningInstance, Credentials> instanceToCredentials;
|
final Function<RunningInstance, Credentials> instanceToCredentials;
|
||||||
final Map<String, Credentials> credentialStore;
|
final Map<String, Credentials> credentialStore;
|
||||||
final Provider<TemplateBuilder> templateBuilderProvider;
|
final Provider<TemplateBuilder> templateBuilderProvider;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
EC2CreateNodesInGroupThenAddToSet(
|
protected EC2CreateNodesInGroupThenAddToSet(
|
||||||
EC2Client client,
|
EC2Client client,
|
||||||
Provider<TemplateBuilder> templateBuilderProvider,
|
Provider<TemplateBuilder> templateBuilderProvider,
|
||||||
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
|
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
|
||||||
@Named("PRESENT") Predicate<RunningInstance> instancePresent,
|
InstancePresent instancePresent, Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
|
||||||
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
|
|
||||||
Function<RunningInstance, Credentials> instanceToCredentials, Map<String, Credentials> credentialStore,
|
Function<RunningInstance, Credentials> instanceToCredentials, Map<String, Credentials> credentialStore,
|
||||||
ComputeUtils utils) {
|
ComputeUtils utils) {
|
||||||
this.client = client;
|
this.client = checkNotNull(client, "client");
|
||||||
this.templateBuilderProvider = templateBuilderProvider;
|
this.templateBuilderProvider = checkNotNull(templateBuilderProvider, "templateBuilderProvider");
|
||||||
this.instancePresent = instancePresent;
|
this.instancePresent = checkNotNull(instancePresent, "instancePresent");
|
||||||
this.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = createKeyPairAndSecurityGroupsAsNeededAndReturncustomize;
|
this.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = checkNotNull(
|
||||||
this.runningInstanceToNodeMetadata = runningInstanceToNodeMetadata;
|
createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
|
||||||
this.instanceToCredentials = instanceToCredentials;
|
"createKeyPairAndSecurityGroupsAsNeededAndReturncustomize");
|
||||||
this.credentialStore = credentialStore;
|
this.runningInstanceToNodeMetadata = checkNotNull(runningInstanceToNodeMetadata, "runningInstanceToNodeMetadata");
|
||||||
this.utils = utils;
|
this.instanceToCredentials = checkNotNull(instanceToCredentials, "instanceToCredentials");
|
||||||
|
this.credentialStore = checkNotNull(credentialStore, "credentialStore");
|
||||||
|
this.utils = checkNotNull(utils, "utils");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Function<RunningInstance, RegionAndName> instanceToRegionAndName = new Function<RunningInstance, RegionAndName>() {
|
||||||
|
@Override
|
||||||
|
public RegionAndName apply(RunningInstance from) {
|
||||||
|
return new RegionAndName(from.getRegion(), from.getId());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<?, Future<Void>> execute(String group, int count, Template template, Set<NodeMetadata> goodNodes,
|
public Map<?, Future<Void>> execute(String group, int count, Template template, Set<NodeMetadata> goodNodes,
|
||||||
Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
|
Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
|
||||||
|
@ -107,18 +116,19 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
|
||||||
template = templateBuilderProvider.get().fromTemplate(template).build();
|
template = templateBuilderProvider.get().fromTemplate(template).build();
|
||||||
Iterable<? extends RunningInstance> started = createKeyPairAndSecurityGroupsAsNeededThenRunInstances(group,
|
Iterable<? extends RunningInstance> started = createKeyPairAndSecurityGroupsAsNeededThenRunInstances(group,
|
||||||
count, template);
|
count, template);
|
||||||
Iterable<String> ids = transform(started, instanceToId);
|
|
||||||
|
Iterable<RegionAndName> ids = transform(started, instanceToRegionAndName);
|
||||||
|
|
||||||
String idsString = Joiner.on(',').join(ids);
|
String idsString = Joiner.on(',').join(ids);
|
||||||
if (Iterables.size(ids) > 0) {
|
if (Iterables.size(ids) > 0) {
|
||||||
logger.debug("<< started instances(%s)", idsString);
|
logger.debug("<< started instances(%s)", idsString);
|
||||||
all(started, instancePresent);
|
all(ids, instancePresent);
|
||||||
logger.debug("<< present instances(%s)", idsString);
|
logger.debug("<< present instances(%s)", idsString);
|
||||||
populateCredentials(started);
|
populateCredentials(started);
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(template.getOptions(),
|
return utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(template.getOptions(), transform(started,
|
||||||
transform(started, runningInstanceToNodeMetadata), goodNodes, badNodes, customizationResponses);
|
runningInstanceToNodeMetadata), goodNodes, badNodes, customizationResponses);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void populateCredentials(Iterable<? extends RunningInstance> started) {
|
protected void populateCredentials(Iterable<? extends RunningInstance> started) {
|
||||||
|
@ -131,19 +141,20 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
|
||||||
if (credentials != null)
|
if (credentials != null)
|
||||||
for (RunningInstance instance : started)
|
for (RunningInstance instance : started)
|
||||||
credentialStore.put("node#" + instance.getRegion() + "/" + instance.getId(), credentials);
|
credentialStore.put("node#" + instance.getRegion() + "/" + instance.getId(), credentials);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO write test for this
|
// TODO write test for this
|
||||||
@VisibleForTesting
|
protected Iterable<? extends RunningInstance> createKeyPairAndSecurityGroupsAsNeededThenRunInstances(String group,
|
||||||
Iterable<? extends RunningInstance> createKeyPairAndSecurityGroupsAsNeededThenRunInstances(String group, int count,
|
int count, Template template) {
|
||||||
Template template) {
|
|
||||||
String region = AWSUtils.getRegionFromLocationOrNull(template.getLocation());
|
String region = AWSUtils.getRegionFromLocationOrNull(template.getLocation());
|
||||||
String zone = getZoneFromLocationOrNull(template.getLocation());
|
String zone = getZoneFromLocationOrNull(template.getLocation());
|
||||||
|
|
||||||
RunInstancesOptions instanceOptions = createKeyPairAndSecurityGroupsAsNeededAndReturncustomize.execute(region,
|
RunInstancesOptions instanceOptions = createKeyPairAndSecurityGroupsAsNeededAndReturncustomize.execute(region,
|
||||||
group, template);
|
group, template);
|
||||||
|
return createNodesInRegionAndZone(region, zone, count, template, instanceOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Iterable<? extends RunningInstance> createNodesInRegionAndZone(String region, String zone, int count,
|
||||||
|
Template template, RunInstancesOptions instanceOptions) {
|
||||||
int countStarted = 0;
|
int countStarted = 0;
|
||||||
int tries = 0;
|
int tries = 0;
|
||||||
Iterable<? extends RunningInstance> started = ImmutableSet.<RunningInstance> of();
|
Iterable<? extends RunningInstance> started = ImmutableSet.<RunningInstance> of();
|
||||||
|
@ -153,10 +164,8 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
|
||||||
logger.debug(">> running %d instance region(%s) zone(%s) ami(%s) params(%s)", count - countStarted, region,
|
logger.debug(">> running %d instance region(%s) zone(%s) ami(%s) params(%s)", count - countStarted, region,
|
||||||
zone, template.getImage().getProviderId(), instanceOptions.buildFormParameters());
|
zone, template.getImage().getProviderId(), instanceOptions.buildFormParameters());
|
||||||
|
|
||||||
started = Iterables.concat(
|
started = Iterables.concat(started, client.getInstanceServices().runInstancesInRegion(region, zone,
|
||||||
started,
|
template.getImage().getProviderId(), 1, count - countStarted, instanceOptions));
|
||||||
client.getInstanceServices().runInstancesInRegion(region, zone, template.getImage().getProviderId(), 1,
|
|
||||||
count - countStarted, instanceOptions));
|
|
||||||
|
|
||||||
countStarted = Iterables.size(started);
|
countStarted = Iterables.size(started);
|
||||||
if (countStarted < count)
|
if (countStarted < count)
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
|
|
||||||
package org.jclouds.ec2.compute.strategy;
|
package org.jclouds.ec2.compute.strategy;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
@ -41,14 +43,13 @@ public class EC2DestroyNodeStrategy implements DestroyNodeStrategy {
|
||||||
@Resource
|
@Resource
|
||||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||||
protected Logger logger = Logger.NULL;
|
protected Logger logger = Logger.NULL;
|
||||||
protected final EC2Client ec2Client;
|
protected final EC2Client client;
|
||||||
protected final GetNodeMetadataStrategy getNode;
|
protected final GetNodeMetadataStrategy getNode;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected EC2DestroyNodeStrategy(EC2Client ec2Client,
|
protected EC2DestroyNodeStrategy(EC2Client client, GetNodeMetadataStrategy getNode) {
|
||||||
GetNodeMetadataStrategy getNodeMetadataStrategy) {
|
this.client = checkNotNull(client, "client");
|
||||||
this.ec2Client = ec2Client;
|
this.getNode = checkNotNull(getNode, "getNode");
|
||||||
this.getNode = getNodeMetadataStrategy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -56,8 +57,11 @@ public class EC2DestroyNodeStrategy implements DestroyNodeStrategy {
|
||||||
String[] parts = AWSUtils.parseHandle(id);
|
String[] parts = AWSUtils.parseHandle(id);
|
||||||
String region = parts[0];
|
String region = parts[0];
|
||||||
String instanceId = parts[1];
|
String instanceId = parts[1];
|
||||||
ec2Client.getInstanceServices().terminateInstancesInRegion(region,
|
destroyInstanceInRegion(region, instanceId);
|
||||||
instanceId);
|
|
||||||
return getNode.getNode(id);
|
return getNode.getNode(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void destroyInstanceInRegion(String region, String instanceId) {
|
||||||
|
client.getInstanceServices().terminateInstancesInRegion(region, instanceId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
package org.jclouds.ec2.compute.strategy;
|
package org.jclouds.ec2.compute.strategy;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static com.google.common.collect.Iterables.getOnlyElement;
|
import static com.google.common.collect.Iterables.getOnlyElement;
|
||||||
|
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
@ -31,7 +32,6 @@ import org.jclouds.compute.domain.NodeMetadata;
|
||||||
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
|
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
|
||||||
import org.jclouds.ec2.EC2Client;
|
import org.jclouds.ec2.EC2Client;
|
||||||
import org.jclouds.ec2.domain.RunningInstance;
|
import org.jclouds.ec2.domain.RunningInstance;
|
||||||
import org.jclouds.ec2.services.InstanceClient;
|
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
|
@ -49,27 +49,26 @@ public class EC2GetNodeMetadataStrategy implements GetNodeMetadataStrategy {
|
||||||
@Inject
|
@Inject
|
||||||
protected EC2GetNodeMetadataStrategy(EC2Client client,
|
protected EC2GetNodeMetadataStrategy(EC2Client client,
|
||||||
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata) {
|
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata) {
|
||||||
this.client = client;
|
this.client = checkNotNull(client, "client");
|
||||||
this.runningInstanceToNodeMetadata = runningInstanceToNodeMetadata;
|
this.runningInstanceToNodeMetadata = checkNotNull(runningInstanceToNodeMetadata, "runningInstanceToNodeMetadata");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NodeMetadata getNode(String id) {
|
public NodeMetadata getNode(String id) {
|
||||||
|
checkNotNull(id, "id");
|
||||||
String[] parts = AWSUtils.parseHandle(id);
|
String[] parts = AWSUtils.parseHandle(id);
|
||||||
String region = parts[0];
|
String region = parts[0];
|
||||||
String instanceId = parts[1];
|
String instanceId = parts[1];
|
||||||
try {
|
try {
|
||||||
RunningInstance runningInstance = getOnlyElement(getAllRunningInstancesInRegion(client.getInstanceServices(),
|
RunningInstance runningInstance = getRunningInstanceInRegion(region, instanceId);
|
||||||
region, instanceId));
|
|
||||||
return runningInstanceToNodeMetadata.apply(runningInstance);
|
return runningInstanceToNodeMetadata.apply(runningInstance);
|
||||||
} catch (NoSuchElementException e) {
|
} catch (NoSuchElementException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Iterable<RunningInstance> getAllRunningInstancesInRegion(InstanceClient client, String region,
|
public RunningInstance getRunningInstanceInRegion(String region, String id) {
|
||||||
String id) {
|
return getOnlyElement(Iterables.concat(client.getInstanceServices().describeInstancesInRegion(region, id)));
|
||||||
return Iterables.concat(client.describeInstancesInRegion(region, id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,10 +19,12 @@
|
||||||
|
|
||||||
package org.jclouds.ec2.compute.strategy;
|
package org.jclouds.ec2.compute.strategy;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
import static com.google.common.base.Predicates.and;
|
||||||
|
import static com.google.common.base.Predicates.notNull;
|
||||||
import static com.google.common.collect.Iterables.concat;
|
import static com.google.common.collect.Iterables.concat;
|
||||||
import static com.google.common.collect.Iterables.filter;
|
import static com.google.common.collect.Iterables.filter;
|
||||||
import static com.google.common.collect.Iterables.transform;
|
import static com.google.common.collect.Iterables.transform;
|
||||||
import static com.google.common.collect.Sets.newLinkedHashSet;
|
|
||||||
import static org.jclouds.concurrent.FutureIterables.transformParallel;
|
import static org.jclouds.concurrent.FutureIterables.transformParallel;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -35,19 +37,20 @@ import javax.inject.Named;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import org.jclouds.Constants;
|
import org.jclouds.Constants;
|
||||||
import org.jclouds.ec2.EC2AsyncClient;
|
|
||||||
import org.jclouds.ec2.domain.Reservation;
|
|
||||||
import org.jclouds.ec2.domain.RunningInstance;
|
|
||||||
import org.jclouds.compute.domain.ComputeMetadata;
|
import org.jclouds.compute.domain.ComputeMetadata;
|
||||||
import org.jclouds.compute.domain.NodeMetadata;
|
import org.jclouds.compute.domain.NodeMetadata;
|
||||||
import org.jclouds.compute.predicates.NodePredicates;
|
import org.jclouds.compute.predicates.NodePredicates;
|
||||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||||
import org.jclouds.compute.strategy.ListNodesStrategy;
|
import org.jclouds.compute.strategy.ListNodesStrategy;
|
||||||
|
import org.jclouds.ec2.EC2AsyncClient;
|
||||||
|
import org.jclouds.ec2.domain.Reservation;
|
||||||
|
import org.jclouds.ec2.domain.RunningInstance;
|
||||||
import org.jclouds.location.Region;
|
import org.jclouds.location.Region;
|
||||||
import org.jclouds.logging.Logger;
|
import org.jclouds.logging.Logger;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -59,19 +62,19 @@ public class EC2ListNodesStrategy implements ListNodesStrategy {
|
||||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||||
protected Logger logger = Logger.NULL;
|
protected Logger logger = Logger.NULL;
|
||||||
|
|
||||||
private final EC2AsyncClient client;
|
protected final EC2AsyncClient client;
|
||||||
private final Set<String> regions;
|
protected final Set<String> regions;
|
||||||
private final Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata;
|
protected final Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata;
|
||||||
private final ExecutorService executor;
|
protected final ExecutorService executor;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected EC2ListNodesStrategy(EC2AsyncClient client, @Region Set<String> regions,
|
protected EC2ListNodesStrategy(EC2AsyncClient client, @Region Set<String> regions,
|
||||||
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
|
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
|
||||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
|
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
|
||||||
this.client = client;
|
this.client = checkNotNull(client, "client");
|
||||||
this.regions = regions;
|
this.regions = checkNotNull(regions, "regions");
|
||||||
this.runningInstanceToNodeMetadata = runningInstanceToNodeMetadata;
|
this.runningInstanceToNodeMetadata = checkNotNull(runningInstanceToNodeMetadata, "runningInstanceToNodeMetadata");
|
||||||
this.executor = executor;
|
this.executor = checkNotNull(executor, "executor");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -81,19 +84,25 @@ public class EC2ListNodesStrategy implements ListNodesStrategy {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<? extends NodeMetadata> listDetailsOnNodesMatching(Predicate<ComputeMetadata> filter) {
|
public Set<? extends NodeMetadata> listDetailsOnNodesMatching(Predicate<ComputeMetadata> filter) {
|
||||||
|
Iterable<? extends RunningInstance> instances = pollRunningInstances();
|
||||||
|
Iterable<? extends NodeMetadata> nodes = filter(transform(filter(instances, notNull()),
|
||||||
|
runningInstanceToNodeMetadata), and(notNull(), filter));
|
||||||
|
return ImmutableSet.copyOf(nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Iterable<? extends RunningInstance> pollRunningInstances() {
|
||||||
Iterable<? extends Set<? extends Reservation<? extends RunningInstance>>> reservations = transformParallel(
|
Iterable<? extends Set<? extends Reservation<? extends RunningInstance>>> reservations = transformParallel(
|
||||||
regions, new Function<String, Future<Set<? extends Reservation<? extends RunningInstance>>>>() {
|
regions, new Function<String, Future<Set<? extends Reservation<? extends RunningInstance>>>>() {
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public Future<Set<? extends Reservation<? extends RunningInstance>>> apply(String from) {
|
public Future<Set<? extends Reservation<? extends RunningInstance>>> apply(String from) {
|
||||||
return (Future<Set<? extends Reservation<? extends RunningInstance>>>) client.getInstanceServices().describeInstancesInRegion(from);
|
return (Future<Set<? extends Reservation<? extends RunningInstance>>>) client
|
||||||
|
.getInstanceServices().describeInstancesInRegion(from);
|
||||||
}
|
}
|
||||||
|
|
||||||
}, executor, null, logger, "reservations");
|
}, executor, null, logger, "reservations");
|
||||||
|
|
||||||
Iterable<? extends RunningInstance> instances = concat(concat(reservations));
|
return concat(concat(reservations));
|
||||||
Iterable<? extends NodeMetadata> nodes = filter(transform(instances, runningInstanceToNodeMetadata), filter);
|
|
||||||
return newLinkedHashSet(nodes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,12 +21,9 @@ package org.jclouds.ec2.compute.util;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import org.jclouds.ec2.domain.RunningInstance;
|
|
||||||
import org.jclouds.domain.Location;
|
import org.jclouds.domain.Location;
|
||||||
import org.jclouds.domain.LocationScope;
|
import org.jclouds.domain.LocationScope;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
|
@ -34,13 +31,6 @@ import com.google.common.base.Function;
|
||||||
@Singleton
|
@Singleton
|
||||||
public class EC2ComputeUtils {
|
public class EC2ComputeUtils {
|
||||||
|
|
||||||
public static Function<RunningInstance, String> instanceToId = new Function<RunningInstance, String>() {
|
|
||||||
@Override
|
|
||||||
public String apply(RunningInstance from) {
|
|
||||||
return from.getId();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public static String getZoneFromLocationOrNull(Location location) {
|
public static String getZoneFromLocationOrNull(Location location) {
|
||||||
return location.getScope() == LocationScope.ZONE ? location.getId() : null;
|
return location.getScope() == LocationScope.ZONE ? location.getId() : null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,9 @@ import com.google.common.collect.Sets;
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
public class RunningInstance implements Comparable<RunningInstance> {
|
public class RunningInstance implements Comparable<RunningInstance> {
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
protected String region;
|
protected String region;
|
||||||
|
@ -265,8 +268,8 @@ public class RunningInstance implements Comparable<RunningInstance> {
|
||||||
this.ipAddress = ipAddress;
|
this.ipAddress = ipAddress;
|
||||||
this.kernelId = kernelId;
|
this.kernelId = kernelId;
|
||||||
this.keyName = keyName;
|
this.keyName = keyName;
|
||||||
this.launchTime = checkNotNull(launchTime, "launchTime");
|
this.launchTime = launchTime;// nullable on spot.
|
||||||
this.availabilityZone = checkNotNull(availabilityZone, "availabilityZone");
|
this.availabilityZone = availabilityZone;// nullable on spot.
|
||||||
this.virtualizationType = virtualizationType;
|
this.virtualizationType = virtualizationType;
|
||||||
this.platform = platform;
|
this.platform = platform;
|
||||||
this.privateDnsName = privateDnsName;// nullable on runinstances.
|
this.privateDnsName = privateDnsName;// nullable on runinstances.
|
||||||
|
|
|
@ -42,8 +42,10 @@ import org.jclouds.domain.Location;
|
||||||
import org.jclouds.domain.LocationBuilder;
|
import org.jclouds.domain.LocationBuilder;
|
||||||
import org.jclouds.domain.LocationScope;
|
import org.jclouds.domain.LocationScope;
|
||||||
import org.jclouds.ec2.EC2Client;
|
import org.jclouds.ec2.EC2Client;
|
||||||
|
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||||
import org.jclouds.ec2.compute.functions.RunningInstanceToNodeMetadata;
|
import org.jclouds.ec2.compute.functions.RunningInstanceToNodeMetadata;
|
||||||
import org.jclouds.ec2.compute.options.EC2TemplateOptions;
|
import org.jclouds.ec2.compute.options.EC2TemplateOptions;
|
||||||
|
import org.jclouds.ec2.compute.predicates.InstancePresent;
|
||||||
import org.jclouds.ec2.domain.Reservation;
|
import org.jclouds.ec2.domain.Reservation;
|
||||||
import org.jclouds.ec2.domain.RunningInstance;
|
import org.jclouds.ec2.domain.RunningInstance;
|
||||||
import org.jclouds.ec2.options.RunInstancesOptions;
|
import org.jclouds.ec2.options.RunInstancesOptions;
|
||||||
|
@ -51,7 +53,6 @@ import org.jclouds.ec2.services.InstanceClient;
|
||||||
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.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
|
@ -61,7 +62,7 @@ import com.google.inject.util.Providers;
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
@Test(groups = "unit")
|
@Test(groups = "unit")
|
||||||
public class EC2RunNodesAndAddToSetStrategyTest {
|
public class EC2CreateNodesInGroupThenAddToSetTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testZoneAsALocation() {
|
public void testZoneAsALocation() {
|
||||||
|
@ -126,10 +127,10 @@ public class EC2RunNodesAndAddToSetStrategyTest {
|
||||||
// simulate a lazy credentials fetch
|
// simulate a lazy credentials fetch
|
||||||
Credentials creds = new Credentials("foo", "bar");
|
Credentials creds = new Credentials("foo", "bar");
|
||||||
expect(strategy.instanceToCredentials.apply(instance)).andReturn(creds);
|
expect(strategy.instanceToCredentials.apply(instance)).andReturn(creds);
|
||||||
expect(instance.getRegion()).andReturn(region);
|
expect(instance.getRegion()).andReturn(region).atLeastOnce();
|
||||||
expect(strategy.credentialStore.put("node#" + region + "/" + instanceCreatedId, creds)).andReturn(null);
|
expect(strategy.credentialStore.put("node#" + region + "/" + instanceCreatedId, creds)).andReturn(null);
|
||||||
|
|
||||||
expect(strategy.instancePresent.apply(instance)).andReturn(true);
|
expect(strategy.instancePresent.apply(new RegionAndName(region, instanceCreatedId))).andReturn(true);
|
||||||
expect(input.template.getOptions()).andReturn(input.options).atLeastOnce();
|
expect(input.template.getOptions()).andReturn(input.options).atLeastOnce();
|
||||||
|
|
||||||
expect(strategy.runningInstanceToNodeMetadata.apply(instance)).andReturn(nodeMetadata);
|
expect(strategy.runningInstanceToNodeMetadata.apply(instance)).andReturn(nodeMetadata);
|
||||||
|
@ -220,13 +221,13 @@ public class EC2RunNodesAndAddToSetStrategyTest {
|
||||||
private EC2CreateNodesInGroupThenAddToSet setupStrategy(TemplateBuilder template) {
|
private EC2CreateNodesInGroupThenAddToSet setupStrategy(TemplateBuilder template) {
|
||||||
EC2Client client = createMock(EC2Client.class);
|
EC2Client client = createMock(EC2Client.class);
|
||||||
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = createMock(CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.class);
|
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = createMock(CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.class);
|
||||||
Predicate<RunningInstance> instanceStateRunning = createMock(Predicate.class);
|
InstancePresent instancePresent = createMock(InstancePresent.class);
|
||||||
RunningInstanceToNodeMetadata runningInstanceToNodeMetadata = createMock(RunningInstanceToNodeMetadata.class);
|
RunningInstanceToNodeMetadata runningInstanceToNodeMetadata = createMock(RunningInstanceToNodeMetadata.class);
|
||||||
Function<RunningInstance, Credentials> instanceToCredentials = createMock(Function.class);
|
Function<RunningInstance, Credentials> instanceToCredentials = createMock(Function.class);
|
||||||
Map<String, Credentials> credentialStore = createMock(Map.class);
|
Map<String, Credentials> credentialStore = createMock(Map.class);
|
||||||
ComputeUtils utils = createMock(ComputeUtils.class);
|
ComputeUtils utils = createMock(ComputeUtils.class);
|
||||||
return new EC2CreateNodesInGroupThenAddToSet(client, Providers.<TemplateBuilder> of(template),
|
return new EC2CreateNodesInGroupThenAddToSet(client, Providers.<TemplateBuilder> of(template),
|
||||||
createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, instanceStateRunning,
|
createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, instancePresent,
|
||||||
runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils);
|
runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils);
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,8 @@ public class NodePresentAndInIntendedState implements Predicate<NodeMetadata> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private NodeMetadata refresh(NodeMetadata node) {
|
private NodeMetadata refresh(NodeMetadata node) {
|
||||||
|
if (node == null || node.getId() == null)
|
||||||
|
return null;
|
||||||
return client.getNodeMetadata(node.getId());
|
return client.getNodeMetadata(node.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import java.util.Set;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.jclouds.aws.ec2.options.RequestSpotInstancesOptions;
|
||||||
import org.jclouds.compute.options.TemplateOptions;
|
import org.jclouds.compute.options.TemplateOptions;
|
||||||
import org.jclouds.domain.Credentials;
|
import org.jclouds.domain.Credentials;
|
||||||
import org.jclouds.ec2.compute.options.EC2TemplateOptions;
|
import org.jclouds.ec2.compute.options.EC2TemplateOptions;
|
||||||
|
@ -73,6 +74,10 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
|
||||||
eTo.noPlacementGroup();
|
eTo.noPlacementGroup();
|
||||||
if (getPlacementGroup() != null)
|
if (getPlacementGroup() != null)
|
||||||
eTo.placementGroup(getPlacementGroup());
|
eTo.placementGroup(getPlacementGroup());
|
||||||
|
if (getSpotPrice() != null)
|
||||||
|
eTo.spotPrice(getSpotPrice());
|
||||||
|
if (getSpotOptions() != null)
|
||||||
|
eTo.spotOptions(getSpotOptions());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,6 +85,8 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
|
||||||
private String placementGroup = null;
|
private String placementGroup = null;
|
||||||
private boolean noPlacementGroup;
|
private boolean noPlacementGroup;
|
||||||
private String subnetId;
|
private String subnetId;
|
||||||
|
private Float spotPrice;
|
||||||
|
private RequestSpotInstancesOptions spotOptions = RequestSpotInstancesOptions.NONE;
|
||||||
|
|
||||||
public static final AWSEC2TemplateOptions NONE = new AWSEC2TemplateOptions();
|
public static final AWSEC2TemplateOptions NONE = new AWSEC2TemplateOptions();
|
||||||
|
|
||||||
|
@ -123,6 +130,22 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the maximum spot price to use
|
||||||
|
*/
|
||||||
|
public AWSEC2TemplateOptions spotPrice(Float spotPrice) {
|
||||||
|
this.spotPrice = spotPrice;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options for starting spot instances
|
||||||
|
*/
|
||||||
|
public AWSEC2TemplateOptions spotOptions(RequestSpotInstancesOptions spotOptions) {
|
||||||
|
this.spotOptions = spotOptions != null ? spotOptions : RequestSpotInstancesOptions.NONE;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
/**
|
/**
|
||||||
* @see EC2TemplateOptions#blockDeviceMappings
|
* @see EC2TemplateOptions#blockDeviceMappings
|
||||||
|
@ -280,12 +303,28 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see TemplateOptions#withSubnetId
|
* @see TemplateOptions#spotPrice
|
||||||
*/
|
*/
|
||||||
public static AWSEC2TemplateOptions subnetId(String subnetId) {
|
public static AWSEC2TemplateOptions subnetId(String subnetId) {
|
||||||
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
|
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
|
||||||
return options.subnetId(subnetId);
|
return options.subnetId(subnetId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see TemplateOptions#spotPrice
|
||||||
|
*/
|
||||||
|
public static AWSEC2TemplateOptions spotPrice(Float spotPrice) {
|
||||||
|
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
|
||||||
|
return options.spotPrice(spotPrice);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see TemplateOptions#spotOptions
|
||||||
|
*/
|
||||||
|
public static AWSEC2TemplateOptions spotOptions(RequestSpotInstancesOptions spotOptions) {
|
||||||
|
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
|
||||||
|
return options.spotOptions(spotOptions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// methods that only facilitate returning the correct object type
|
// methods that only facilitate returning the correct object type
|
||||||
|
@ -525,6 +564,20 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
|
||||||
return subnetId;
|
return subnetId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return maximum spot price or null.
|
||||||
|
*/
|
||||||
|
public Float getSpotPrice() {
|
||||||
|
return spotPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return options for controlling spot instance requests.
|
||||||
|
*/
|
||||||
|
public RequestSpotInstancesOptions getSpotOptions() {
|
||||||
|
return spotOptions;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
|
@ -532,6 +585,8 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
|
||||||
result = prime * result + (monitoringEnabled ? 1231 : 1237);
|
result = prime * result + (monitoringEnabled ? 1231 : 1237);
|
||||||
result = prime * result + (noPlacementGroup ? 1231 : 1237);
|
result = prime * result + (noPlacementGroup ? 1231 : 1237);
|
||||||
result = prime * result + ((placementGroup == null) ? 0 : placementGroup.hashCode());
|
result = prime * result + ((placementGroup == null) ? 0 : placementGroup.hashCode());
|
||||||
|
result = prime * result + ((spotOptions == null) ? 0 : spotOptions.hashCode());
|
||||||
|
result = prime * result + ((spotPrice == null) ? 0 : spotPrice.hashCode());
|
||||||
result = prime * result + ((subnetId == null) ? 0 : subnetId.hashCode());
|
result = prime * result + ((subnetId == null) ? 0 : subnetId.hashCode());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -554,6 +609,16 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
|
||||||
return false;
|
return false;
|
||||||
} else if (!placementGroup.equals(other.placementGroup))
|
} else if (!placementGroup.equals(other.placementGroup))
|
||||||
return false;
|
return false;
|
||||||
|
if (spotOptions == null) {
|
||||||
|
if (other.spotOptions != null)
|
||||||
|
return false;
|
||||||
|
} else if (!spotOptions.equals(other.spotOptions))
|
||||||
|
return false;
|
||||||
|
if (spotPrice == null) {
|
||||||
|
if (other.spotPrice != null)
|
||||||
|
return false;
|
||||||
|
} else if (!spotPrice.equals(other.spotPrice))
|
||||||
|
return false;
|
||||||
if (subnetId == null) {
|
if (subnetId == null) {
|
||||||
if (other.subnetId != null)
|
if (other.subnetId != null)
|
||||||
return false;
|
return false;
|
||||||
|
@ -568,7 +633,8 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
|
||||||
return "[groupIds=" + getGroupIds() + ", keyPair=" + getKeyPair() + ", noKeyPair="
|
return "[groupIds=" + getGroupIds() + ", keyPair=" + getKeyPair() + ", noKeyPair="
|
||||||
+ !shouldAutomaticallyCreateKeyPair() + ", monitoringEnabled=" + monitoringEnabled + ", placementGroup="
|
+ !shouldAutomaticallyCreateKeyPair() + ", monitoringEnabled=" + monitoringEnabled + ", placementGroup="
|
||||||
+ placementGroup + ", noPlacementGroup=" + noPlacementGroup + ", subnetId=" + subnetId + ", userData="
|
+ placementGroup + ", noPlacementGroup=" + noPlacementGroup + ", subnetId=" + subnetId + ", userData="
|
||||||
+ Arrays.toString(getUserData()) + ", blockDeviceMappings=" + getBlockDeviceMappings() + "]";
|
+ Arrays.toString(getUserData()) + ", blockDeviceMappings=" + getBlockDeviceMappings() + ", spotPrice="
|
||||||
|
+ spotPrice + ", spotOptions=" + spotOptions + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,14 +22,26 @@ package org.jclouds.aws.ec2.compute.config;
|
||||||
import static org.jclouds.compute.domain.OsFamily.AMZN_LINUX;
|
import static org.jclouds.compute.domain.OsFamily.AMZN_LINUX;
|
||||||
|
|
||||||
import org.jclouds.aws.ec2.compute.AWSEC2TemplateBuilderImpl;
|
import org.jclouds.aws.ec2.compute.AWSEC2TemplateBuilderImpl;
|
||||||
|
import org.jclouds.aws.ec2.compute.functions.AWSRunningInstanceToNodeMetadata;
|
||||||
|
import org.jclouds.aws.ec2.compute.predicates.AWSEC2InstancePresent;
|
||||||
|
import org.jclouds.aws.ec2.compute.strategy.AWSEC2CreateNodesInGroupThenAddToSet;
|
||||||
|
import org.jclouds.aws.ec2.compute.strategy.AWSEC2DestroyNodeStrategy;
|
||||||
|
import org.jclouds.aws.ec2.compute.strategy.AWSEC2GetNodeMetadataStrategy;
|
||||||
|
import org.jclouds.aws.ec2.compute.strategy.AWSEC2ListNodesStrategy;
|
||||||
import org.jclouds.aws.ec2.compute.strategy.AWSEC2ReviseParsedImage;
|
import org.jclouds.aws.ec2.compute.strategy.AWSEC2ReviseParsedImage;
|
||||||
import org.jclouds.aws.ec2.compute.strategy.CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions;
|
import org.jclouds.aws.ec2.compute.strategy.CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions;
|
||||||
import org.jclouds.aws.ec2.compute.suppliers.AWSEC2HardwareSupplier;
|
import org.jclouds.aws.ec2.compute.suppliers.AWSEC2HardwareSupplier;
|
||||||
import org.jclouds.aws.ec2.compute.suppliers.AWSRegionAndNameToImageSupplier;
|
import org.jclouds.aws.ec2.compute.suppliers.AWSRegionAndNameToImageSupplier;
|
||||||
import org.jclouds.compute.domain.TemplateBuilder;
|
import org.jclouds.compute.domain.TemplateBuilder;
|
||||||
import org.jclouds.ec2.compute.config.EC2ComputeServiceContextModule;
|
import org.jclouds.ec2.compute.config.EC2ComputeServiceContextModule;
|
||||||
|
import org.jclouds.ec2.compute.functions.RunningInstanceToNodeMetadata;
|
||||||
import org.jclouds.ec2.compute.internal.EC2TemplateBuilderImpl;
|
import org.jclouds.ec2.compute.internal.EC2TemplateBuilderImpl;
|
||||||
|
import org.jclouds.ec2.compute.predicates.InstancePresent;
|
||||||
import org.jclouds.ec2.compute.strategy.CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions;
|
import org.jclouds.ec2.compute.strategy.CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions;
|
||||||
|
import org.jclouds.ec2.compute.strategy.EC2CreateNodesInGroupThenAddToSet;
|
||||||
|
import org.jclouds.ec2.compute.strategy.EC2DestroyNodeStrategy;
|
||||||
|
import org.jclouds.ec2.compute.strategy.EC2GetNodeMetadataStrategy;
|
||||||
|
import org.jclouds.ec2.compute.strategy.EC2ListNodesStrategy;
|
||||||
import org.jclouds.ec2.compute.strategy.ReviseParsedImage;
|
import org.jclouds.ec2.compute.strategy.ReviseParsedImage;
|
||||||
import org.jclouds.ec2.compute.suppliers.EC2HardwareSupplier;
|
import org.jclouds.ec2.compute.suppliers.EC2HardwareSupplier;
|
||||||
import org.jclouds.ec2.compute.suppliers.RegionAndNameToImageSupplier;
|
import org.jclouds.ec2.compute.suppliers.RegionAndNameToImageSupplier;
|
||||||
|
@ -56,6 +68,12 @@ public class AWSEC2ComputeServiceContextModule extends EC2ComputeServiceContextM
|
||||||
bind(EC2HardwareSupplier.class).to(AWSEC2HardwareSupplier.class);
|
bind(EC2HardwareSupplier.class).to(AWSEC2HardwareSupplier.class);
|
||||||
bind(RegionAndNameToImageSupplier.class).to(AWSRegionAndNameToImageSupplier.class);
|
bind(RegionAndNameToImageSupplier.class).to(AWSRegionAndNameToImageSupplier.class);
|
||||||
bind(EC2TemplateBuilderImpl.class).to(AWSEC2TemplateBuilderImpl.class);
|
bind(EC2TemplateBuilderImpl.class).to(AWSEC2TemplateBuilderImpl.class);
|
||||||
|
bind(EC2GetNodeMetadataStrategy.class).to(AWSEC2GetNodeMetadataStrategy.class);
|
||||||
|
bind(EC2ListNodesStrategy.class).to(AWSEC2ListNodesStrategy.class);
|
||||||
|
bind(EC2DestroyNodeStrategy.class).to(AWSEC2DestroyNodeStrategy.class);
|
||||||
|
bind(InstancePresent.class).to(AWSEC2InstancePresent.class);
|
||||||
|
bind(EC2CreateNodesInGroupThenAddToSet.class).to(AWSEC2CreateNodesInGroupThenAddToSet.class);
|
||||||
|
bind(RunningInstanceToNodeMetadata.class).to(AWSRunningInstanceToNodeMetadata.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jclouds.aws.ec2.compute.functions;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import org.jclouds.aws.ec2.domain.AWSRunningInstance;
|
||||||
|
import org.jclouds.collect.Memoized;
|
||||||
|
import org.jclouds.compute.domain.Hardware;
|
||||||
|
import org.jclouds.compute.domain.Image;
|
||||||
|
import org.jclouds.compute.domain.NodeMetadataBuilder;
|
||||||
|
import org.jclouds.compute.domain.NodeState;
|
||||||
|
import org.jclouds.domain.Credentials;
|
||||||
|
import org.jclouds.domain.Location;
|
||||||
|
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||||
|
import org.jclouds.ec2.compute.functions.RunningInstanceToNodeMetadata;
|
||||||
|
import org.jclouds.ec2.domain.InstanceState;
|
||||||
|
import org.jclouds.ec2.domain.RunningInstance;
|
||||||
|
|
||||||
|
import com.google.common.base.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class AWSRunningInstanceToNodeMetadata extends RunningInstanceToNodeMetadata {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected AWSRunningInstanceToNodeMetadata(Map<InstanceState, NodeState> instanceToNodeState,
|
||||||
|
Map<String, Credentials> credentialStore, Map<RegionAndName, Image> instanceToImage,
|
||||||
|
@Memoized Supplier<Set<? extends Location>> locations, @Memoized Supplier<Set<? extends Hardware>> hardware) {
|
||||||
|
super(instanceToNodeState, credentialStore, instanceToImage, locations, hardware);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addCredentialsForInstance(NodeMetadataBuilder builder, RunningInstance instance) {
|
||||||
|
Credentials creds = credentialStore.get("node#" + instance.getRegion() + "/" + instance.getId());
|
||||||
|
String spotRequestId = AWSRunningInstance.class.cast(instance).getSpotInstanceRequestId();
|
||||||
|
if (creds == null && spotRequestId != null) {
|
||||||
|
creds = credentialStore.get("node#" + instance.getRegion() + "/" + spotRequestId);
|
||||||
|
if (creds != null)
|
||||||
|
credentialStore.put("node#" + instance.getRegion() + "/" + instance.getId(), creds);
|
||||||
|
}
|
||||||
|
if (creds != null)
|
||||||
|
builder.credentials(creds);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jclouds.aws.ec2.compute.predicates;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import org.jclouds.aws.ec2.AWSEC2Client;
|
||||||
|
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||||
|
import org.jclouds.ec2.compute.predicates.InstancePresent;
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class AWSEC2InstancePresent extends InstancePresent {
|
||||||
|
|
||||||
|
private final AWSEC2Client client;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public AWSEC2InstancePresent(AWSEC2Client client) {
|
||||||
|
super(client);
|
||||||
|
this.client = checkNotNull(client, "client");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void refresh(RegionAndName instance) {
|
||||||
|
if (instance.getName().indexOf("sir-") != 0)
|
||||||
|
super.refresh(instance);
|
||||||
|
else
|
||||||
|
Iterables.getOnlyElement(client.getSpotInstanceServices().describeSpotInstanceRequestsInRegion(
|
||||||
|
instance.getRegion(), instance.getName()));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jclouds.aws.ec2.compute.strategy;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Named;
|
||||||
|
import javax.inject.Provider;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import org.jclouds.aws.ec2.AWSEC2Client;
|
||||||
|
import org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions;
|
||||||
|
import org.jclouds.aws.ec2.compute.predicates.AWSEC2InstancePresent;
|
||||||
|
import org.jclouds.aws.ec2.domain.LaunchSpecification;
|
||||||
|
import org.jclouds.aws.ec2.functions.SpotInstanceRequestToAWSRunningInstance;
|
||||||
|
import org.jclouds.aws.ec2.options.AWSRunInstancesOptions;
|
||||||
|
import org.jclouds.aws.ec2.options.RequestSpotInstancesOptions;
|
||||||
|
import org.jclouds.compute.domain.NodeMetadata;
|
||||||
|
import org.jclouds.compute.domain.Template;
|
||||||
|
import org.jclouds.compute.domain.TemplateBuilder;
|
||||||
|
import org.jclouds.compute.options.TemplateOptions;
|
||||||
|
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||||
|
import org.jclouds.compute.util.ComputeUtils;
|
||||||
|
import org.jclouds.domain.Credentials;
|
||||||
|
import org.jclouds.ec2.compute.strategy.EC2CreateNodesInGroupThenAddToSet;
|
||||||
|
import org.jclouds.ec2.domain.RunningInstance;
|
||||||
|
import org.jclouds.ec2.options.RunInstancesOptions;
|
||||||
|
import org.jclouds.logging.Logger;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class AWSEC2CreateNodesInGroupThenAddToSet extends EC2CreateNodesInGroupThenAddToSet {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||||
|
protected Logger logger = Logger.NULL;
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
final AWSEC2Client client;
|
||||||
|
final SpotInstanceRequestToAWSRunningInstance spotConverter;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected AWSEC2CreateNodesInGroupThenAddToSet(
|
||||||
|
AWSEC2Client client,
|
||||||
|
Provider<TemplateBuilder> templateBuilderProvider,
|
||||||
|
CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
|
||||||
|
AWSEC2InstancePresent instancePresent,
|
||||||
|
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
|
||||||
|
Function<RunningInstance, Credentials> instanceToCredentials, Map<String, Credentials> credentialStore,
|
||||||
|
ComputeUtils utils, SpotInstanceRequestToAWSRunningInstance spotConverter) {
|
||||||
|
|
||||||
|
super(client, templateBuilderProvider, createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, instancePresent,
|
||||||
|
runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils);
|
||||||
|
this.client = checkNotNull(client, "client");
|
||||||
|
this.spotConverter = checkNotNull(spotConverter, "spotConverter");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Iterable<? extends RunningInstance> createNodesInRegionAndZone(String region, String zone, 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();
|
||||||
|
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);
|
||||||
|
|
||||||
|
return Iterables.transform(client.getSpotInstanceServices().requestSpotInstancesInRegion(region, spotPrice,
|
||||||
|
count, spec, options), spotConverter);
|
||||||
|
} else {
|
||||||
|
return super.createNodesInRegionAndZone(zone, zone, count, template, instanceOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Float getSpotPriceOrNull(TemplateOptions options) {
|
||||||
|
return options instanceof AWSEC2TemplateOptions ? AWSEC2TemplateOptions.class.cast(options).getSpotPrice() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package org.jclouds.aws.ec2.compute.strategy;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import org.jclouds.aws.ec2.AWSEC2Client;
|
||||||
|
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
|
||||||
|
import org.jclouds.ec2.compute.strategy.EC2DestroyNodeStrategy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class AWSEC2DestroyNodeStrategy extends EC2DestroyNodeStrategy {
|
||||||
|
|
||||||
|
protected final AWSEC2Client client;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected AWSEC2DestroyNodeStrategy(AWSEC2Client client, GetNodeMetadataStrategy getNode) {
|
||||||
|
super(client, getNode);
|
||||||
|
this.client = checkNotNull(client, "client");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void destroyInstanceInRegion(String region, String id) {
|
||||||
|
if (id.indexOf("sir-") != 0) {
|
||||||
|
super.destroyInstanceInRegion(region, id);
|
||||||
|
} else {
|
||||||
|
client.getSpotInstanceServices().cancelSpotInstanceRequestsInRegion(region, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jclouds.aws.ec2.compute.strategy;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
import static com.google.common.collect.Iterables.getOnlyElement;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import org.jclouds.aws.ec2.AWSEC2Client;
|
||||||
|
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
|
||||||
|
import org.jclouds.aws.ec2.functions.SpotInstanceRequestToAWSRunningInstance;
|
||||||
|
import org.jclouds.compute.domain.NodeMetadata;
|
||||||
|
import org.jclouds.ec2.compute.strategy.EC2GetNodeMetadataStrategy;
|
||||||
|
import org.jclouds.ec2.domain.RunningInstance;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class AWSEC2GetNodeMetadataStrategy extends EC2GetNodeMetadataStrategy {
|
||||||
|
|
||||||
|
private final AWSEC2Client client;
|
||||||
|
private final SpotInstanceRequestToAWSRunningInstance spotConverter;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected AWSEC2GetNodeMetadataStrategy(AWSEC2Client client,
|
||||||
|
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
|
||||||
|
SpotInstanceRequestToAWSRunningInstance spotConverter) {
|
||||||
|
super(client, runningInstanceToNodeMetadata);
|
||||||
|
this.client = checkNotNull(client, "client");
|
||||||
|
this.spotConverter = checkNotNull(spotConverter, "spotConverter");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RunningInstance getRunningInstanceInRegion(String region, String id) {
|
||||||
|
if (id.indexOf("sir-") != 0)
|
||||||
|
return super.getRunningInstanceInRegion(region, id);
|
||||||
|
SpotInstanceRequest spot = getOnlyElement(client.getSpotInstanceServices().describeSpotInstanceRequestsInRegion(
|
||||||
|
region, id));
|
||||||
|
if (spot.getState() == SpotInstanceRequest.State.ACTIVE)
|
||||||
|
return super.getRunningInstanceInRegion(region, spot.getInstanceId());
|
||||||
|
else
|
||||||
|
return spotConverter.apply(spot);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jclouds.aws.ec2.compute.strategy;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
import static com.google.common.base.Predicates.notNull;
|
||||||
|
import static com.google.common.collect.Iterables.concat;
|
||||||
|
import static com.google.common.collect.Iterables.filter;
|
||||||
|
import static com.google.common.collect.Iterables.transform;
|
||||||
|
import static org.jclouds.concurrent.FutureIterables.transformParallel;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Named;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import org.jclouds.Constants;
|
||||||
|
import org.jclouds.aws.ec2.AWSEC2AsyncClient;
|
||||||
|
import org.jclouds.aws.ec2.domain.AWSRunningInstance;
|
||||||
|
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
|
||||||
|
import org.jclouds.aws.ec2.functions.SpotInstanceRequestToAWSRunningInstance;
|
||||||
|
import org.jclouds.compute.domain.NodeMetadata;
|
||||||
|
import org.jclouds.ec2.compute.strategy.EC2ListNodesStrategy;
|
||||||
|
import org.jclouds.ec2.domain.RunningInstance;
|
||||||
|
import org.jclouds.location.Region;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class AWSEC2ListNodesStrategy extends EC2ListNodesStrategy {
|
||||||
|
|
||||||
|
protected final AWSEC2AsyncClient client;
|
||||||
|
protected final SpotInstanceRequestToAWSRunningInstance spotConverter;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected AWSEC2ListNodesStrategy(AWSEC2AsyncClient client, @Region Set<String> regions,
|
||||||
|
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
|
||||||
|
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor,
|
||||||
|
SpotInstanceRequestToAWSRunningInstance spotConverter) {
|
||||||
|
super(client, regions, runningInstanceToNodeMetadata, executor);
|
||||||
|
this.client = checkNotNull(client, "client");
|
||||||
|
this.spotConverter = checkNotNull(spotConverter, "spotConverter");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Iterable<? extends RunningInstance> pollRunningInstances() {
|
||||||
|
Iterable<? extends AWSRunningInstance> spots = filter(transform(concat(transformParallel(regions,
|
||||||
|
new Function<String, Future<Set<SpotInstanceRequest>>>() {
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public Future<Set<SpotInstanceRequest>> apply(String from) {
|
||||||
|
return (Future<Set<SpotInstanceRequest>>) client.getSpotInstanceServices()
|
||||||
|
.describeSpotInstanceRequestsInRegion(from);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, executor, null, logger, "reservations")), spotConverter), notNull());
|
||||||
|
|
||||||
|
return concat(super.pollRunningInstances(), spots);
|
||||||
|
}
|
||||||
|
}
|
|
@ -42,6 +42,9 @@ import com.google.common.collect.Sets;
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
public class AWSRunningInstance extends RunningInstance {
|
public class AWSRunningInstance extends RunningInstance {
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
public static class Builder extends org.jclouds.ec2.domain.RunningInstance.Builder {
|
public static class Builder extends org.jclouds.ec2.domain.RunningInstance.Builder {
|
||||||
private MonitoringState monitoringState;
|
private MonitoringState monitoringState;
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jclouds.aws.ec2.functions;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import org.jclouds.aws.ec2.domain.AWSRunningInstance;
|
||||||
|
import org.jclouds.aws.ec2.domain.LaunchSpecification;
|
||||||
|
import org.jclouds.aws.ec2.domain.MonitoringState;
|
||||||
|
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
|
||||||
|
import org.jclouds.ec2.domain.InstanceState;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class SpotInstanceRequestToAWSRunningInstance implements Function<SpotInstanceRequest, AWSRunningInstance> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AWSRunningInstance apply(SpotInstanceRequest request) {
|
||||||
|
if (request == null)
|
||||||
|
return null;
|
||||||
|
if (request.getState() != SpotInstanceRequest.State.OPEN)
|
||||||
|
return null;
|
||||||
|
AWSRunningInstance.Builder builder = AWSRunningInstance.builder();
|
||||||
|
builder.spotInstanceRequestId(request.getId());
|
||||||
|
builder.instanceId(request.getId());
|
||||||
|
builder.instanceState(InstanceState.PENDING);
|
||||||
|
builder.region(request.getRegion());
|
||||||
|
LaunchSpecification spec = request.getLaunchSpecification();
|
||||||
|
builder.availabilityZone(spec.getAvailabilityZone());
|
||||||
|
// TODO convert
|
||||||
|
// builder.devices(spec.getBlockDeviceMappings());
|
||||||
|
builder.groupIds(spec.getGroupIds());
|
||||||
|
builder.imageId(spec.getImageId());
|
||||||
|
builder.instanceType(spec.getInstanceType());
|
||||||
|
builder.kernelId(spec.getKernelId());
|
||||||
|
builder.keyName(spec.getKeyName());
|
||||||
|
builder.ramdiskId(spec.getRamdiskId());
|
||||||
|
builder.monitoringState(Boolean.TRUE.equals(spec.isMonitoringEnabled()) ? MonitoringState.PENDING
|
||||||
|
: MonitoringState.DISABLED);
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -23,10 +23,13 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jclouds.aws.ec2.domain.LaunchSpecification;
|
||||||
import org.jclouds.ec2.domain.BlockDeviceMapping;
|
import org.jclouds.ec2.domain.BlockDeviceMapping;
|
||||||
import org.jclouds.ec2.domain.InstanceType;
|
import org.jclouds.ec2.domain.InstanceType;
|
||||||
import org.jclouds.ec2.options.RunInstancesOptions;
|
import org.jclouds.ec2.options.RunInstancesOptions;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains options supported in the Form API for the RunInstances operation. <h2>
|
* Contains options supported in the Form API for the RunInstances operation. <h2>
|
||||||
* Usage</h2> The recommended way to instantiate a RunInstancesOptions object is to statically
|
* Usage</h2> The recommended way to instantiate a RunInstancesOptions object is to statically
|
||||||
|
@ -46,6 +49,7 @@ import org.jclouds.ec2.options.RunInstancesOptions;
|
||||||
* />
|
* />
|
||||||
*/
|
*/
|
||||||
public class AWSRunInstancesOptions extends RunInstancesOptions {
|
public class AWSRunInstancesOptions extends RunInstancesOptions {
|
||||||
|
private LaunchSpecification.Builder launchSpecificationBuilder = LaunchSpecification.builder();
|
||||||
public static final AWSRunInstancesOptions NONE = new AWSRunInstancesOptions();
|
public static final AWSRunInstancesOptions NONE = new AWSRunInstancesOptions();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -60,22 +64,15 @@ public class AWSRunInstancesOptions extends RunInstancesOptions {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
String getPlacementGroup() {
|
|
||||||
return getFirstFormOrNull("Placement.GroupName");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables monitoring for the instance.
|
* Enables monitoring for the instance.
|
||||||
*/
|
*/
|
||||||
public AWSRunInstancesOptions enableMonitoring() {
|
public AWSRunInstancesOptions enableMonitoring() {
|
||||||
formParameters.put("Monitoring.Enabled", "true");
|
formParameters.put("Monitoring.Enabled", "true");
|
||||||
|
launchSpecificationBuilder.monitoringEnabled(true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
String getMonitoringEnabled() {
|
|
||||||
return getFirstFormOrNull("Monitoring.Enabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies the subnet ID within which to launch the instance(s) for Amazon Virtual Private
|
* Specifies the subnet ID within which to launch the instance(s) for Amazon Virtual Private
|
||||||
* Cloud.
|
* Cloud.
|
||||||
|
@ -85,10 +82,6 @@ public class AWSRunInstancesOptions extends RunInstancesOptions {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
String getSubnetId() {
|
|
||||||
return getFirstFormOrNull("SubnetId");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Builder extends RunInstancesOptions.Builder {
|
public static class Builder extends RunInstancesOptions.Builder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -175,46 +168,63 @@ public class AWSRunInstancesOptions extends RunInstancesOptions {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AWSRunInstancesOptions withBlockDeviceMappings(Set<? extends BlockDeviceMapping> mappings) {
|
public AWSRunInstancesOptions withBlockDeviceMappings(Set<? extends BlockDeviceMapping> mappings) {
|
||||||
|
launchSpecificationBuilder.blockDeviceMappings(mappings);
|
||||||
return AWSRunInstancesOptions.class.cast(super.withBlockDeviceMappings(mappings));
|
return AWSRunInstancesOptions.class.cast(super.withBlockDeviceMappings(mappings));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AWSRunInstancesOptions withKernelId(String kernelId) {
|
public AWSRunInstancesOptions withKernelId(String kernelId) {
|
||||||
|
launchSpecificationBuilder.kernelId(kernelId);
|
||||||
return AWSRunInstancesOptions.class.cast(super.withKernelId(kernelId));
|
return AWSRunInstancesOptions.class.cast(super.withKernelId(kernelId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AWSRunInstancesOptions withKeyName(String keyName) {
|
public AWSRunInstancesOptions withKeyName(String keyName) {
|
||||||
|
launchSpecificationBuilder.keyName(keyName);
|
||||||
return AWSRunInstancesOptions.class.cast(super.withKeyName(keyName));
|
return AWSRunInstancesOptions.class.cast(super.withKeyName(keyName));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AWSRunInstancesOptions withRamdisk(String ramDiskId) {
|
public AWSRunInstancesOptions withRamdisk(String ramDiskId) {
|
||||||
|
launchSpecificationBuilder.ramdiskId(ramDiskId);
|
||||||
return AWSRunInstancesOptions.class.cast(super.withRamdisk(ramDiskId));
|
return AWSRunInstancesOptions.class.cast(super.withRamdisk(ramDiskId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AWSRunInstancesOptions withSecurityGroup(String securityGroup) {
|
public AWSRunInstancesOptions withSecurityGroup(String securityGroup) {
|
||||||
|
launchSpecificationBuilder.groupId(securityGroup);
|
||||||
return AWSRunInstancesOptions.class.cast(super.withSecurityGroup(securityGroup));
|
return AWSRunInstancesOptions.class.cast(super.withSecurityGroup(securityGroup));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AWSRunInstancesOptions withSecurityGroups(Iterable<String> securityGroups) {
|
public AWSRunInstancesOptions withSecurityGroups(Iterable<String> securityGroups) {
|
||||||
|
launchSpecificationBuilder.groupIds(securityGroups);
|
||||||
return AWSRunInstancesOptions.class.cast(super.withSecurityGroups(securityGroups));
|
return AWSRunInstancesOptions.class.cast(super.withSecurityGroups(securityGroups));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AWSRunInstancesOptions withSecurityGroups(String... securityGroups) {
|
public AWSRunInstancesOptions withSecurityGroups(String... securityGroups) {
|
||||||
|
launchSpecificationBuilder.groupIds(ImmutableSet.copyOf(securityGroups));
|
||||||
return AWSRunInstancesOptions.class.cast(super.withSecurityGroups(securityGroups));
|
return AWSRunInstancesOptions.class.cast(super.withSecurityGroups(securityGroups));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AWSRunInstancesOptions withUserData(byte[] unencodedData) {
|
public AWSRunInstancesOptions withUserData(byte[] unencodedData) {
|
||||||
|
launchSpecificationBuilder.userData(unencodedData);
|
||||||
return AWSRunInstancesOptions.class.cast(super.withUserData(unencodedData));
|
return AWSRunInstancesOptions.class.cast(super.withUserData(unencodedData));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AWSRunInstancesOptions asType(String type) {
|
public AWSRunInstancesOptions asType(String type) {
|
||||||
|
launchSpecificationBuilder.instanceType(type);
|
||||||
return AWSRunInstancesOptions.class.cast(super.asType(type));
|
return AWSRunInstancesOptions.class.cast(super.asType(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized LaunchSpecification.Builder getLaunchSpecificationBuilder() {
|
||||||
|
try {
|
||||||
|
return launchSpecificationBuilder.imageId("fake").build().toBuilder().imageId(null);
|
||||||
|
} finally {
|
||||||
|
launchSpecificationBuilder.imageId(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,7 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
|
||||||
options.as(AWSEC2TemplateOptions.class).securityGroups(group);
|
options.as(AWSEC2TemplateOptions.class).securityGroups(group);
|
||||||
options.as(AWSEC2TemplateOptions.class).keyPair(group);
|
options.as(AWSEC2TemplateOptions.class).keyPair(group);
|
||||||
options.as(AWSEC2TemplateOptions.class).enableMonitoring();
|
options.as(AWSEC2TemplateOptions.class).enableMonitoring();
|
||||||
|
options.as(AWSEC2TemplateOptions.class).spotPrice(0.3f);
|
||||||
|
|
||||||
String startedId = null;
|
String startedId = null;
|
||||||
try {
|
try {
|
||||||
|
@ -117,8 +118,8 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// make sure we made our dummy group and also let in the user's group
|
// make sure we made our dummy group and also let in the user's group
|
||||||
assertEquals(Sets.newTreeSet(instance.getGroupIds()),
|
assertEquals(Sets.newTreeSet(instance.getGroupIds()), ImmutableSortedSet.<String> of("jclouds#" + group + "#"
|
||||||
ImmutableSortedSet.<String> of("jclouds#" + group + "#" + instance.getRegion(), group));
|
+ instance.getRegion(), group));
|
||||||
|
|
||||||
// make sure our dummy group has no rules
|
// make sure our dummy group has no rules
|
||||||
SecurityGroup secgroup = Iterables.getOnlyElement(securityGroupClient.describeSecurityGroupsInRegion(null,
|
SecurityGroup secgroup = Iterables.getOnlyElement(securityGroupClient.describeSecurityGroupsInRegion(null,
|
||||||
|
@ -126,8 +127,8 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
|
||||||
assert secgroup.getIpPermissions().size() == 0 : secgroup;
|
assert secgroup.getIpPermissions().size() == 0 : secgroup;
|
||||||
|
|
||||||
// try to run a script with the original keyPair
|
// try to run a script with the original keyPair
|
||||||
runScriptWithCreds(group, first.getOperatingSystem(),
|
runScriptWithCreds(group, first.getOperatingSystem(), new Credentials(first.getCredentials().identity, result
|
||||||
new Credentials(first.getCredentials().identity, result.getKeyMaterial()));
|
.getKeyMaterial()));
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
client.destroyNodesMatching(NodePredicates.inGroup(group));
|
client.destroyNodesMatching(NodePredicates.inGroup(group));
|
||||||
|
@ -157,7 +158,7 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
|
||||||
|
|
||||||
TemplateOptions options = client.templateOptions();
|
TemplateOptions options = client.templateOptions();
|
||||||
|
|
||||||
options.as(AWSEC2TemplateOptions.class).subnetId(subnetId);
|
options.as(AWSEC2TemplateOptions.class).subnetId(subnetId).spotPrice(0.3f);
|
||||||
|
|
||||||
String startedId = null;
|
String startedId = null;
|
||||||
String nodeId = null;
|
String nodeId = null;
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Cloud Conscious, LLC. .info@cloudconscious.com("
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jclouds.aws.ec2.functions;
|
||||||
|
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
import org.jclouds.aws.ec2.domain.AWSRunningInstance;
|
||||||
|
import org.jclouds.aws.ec2.domain.LaunchSpecification;
|
||||||
|
import org.jclouds.aws.ec2.domain.MonitoringState;
|
||||||
|
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
|
||||||
|
import org.jclouds.aws.ec2.functions.SpotInstanceRequestToAWSRunningInstance;
|
||||||
|
import org.jclouds.date.internal.SimpleDateFormatDateService;
|
||||||
|
import org.jclouds.ec2.domain.InstanceState;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests behavior of {@code SpotInstanceRequestToAWSRunningInstance}
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
|
||||||
|
@Test(groups = "unit", testName = "SpotInstanceRequestToAWSRunningInstanceTest")
|
||||||
|
public class SpotInstanceRequestToAWSRunningInstanceTest {
|
||||||
|
|
||||||
|
public void testConvert() {
|
||||||
|
|
||||||
|
SpotInstanceRequest input = SpotInstanceRequest.builder().region("us-east-1").id("sir-228e6406")
|
||||||
|
.spotPrice(0.001f).type(SpotInstanceRequest.Type.ONE_TIME).state(SpotInstanceRequest.State.OPEN)
|
||||||
|
.launchSpecification(
|
||||||
|
LaunchSpecification.builder().imageId("ami-595a0a1c").groupId("default").instanceType(
|
||||||
|
"m1.large").mapNewVolumeToDevice("/dev/sda1", 1, true).mapEBSSnapshotToDevice(
|
||||||
|
"/dev/sda2", "snap-1ea27576", 1, true).mapEphemeralDeviceToDevice("/dev/sda3", "vre1")
|
||||||
|
.monitoringEnabled(false).build()).createTime(
|
||||||
|
new SimpleDateFormatDateService().iso8601DateParse("2011-03-08T03:30:36.000Z"))
|
||||||
|
.productDescription("Linux/UNIX").build();
|
||||||
|
|
||||||
|
assertEquals(new SpotInstanceRequestToAWSRunningInstance().apply(input), AWSRunningInstance.builder().region(
|
||||||
|
"us-east-1").instanceId("sir-228e6406").spotInstanceRequestId("sir-228e6406").instanceState(
|
||||||
|
InstanceState.PENDING).imageId("ami-595a0a1c").groupId("default").instanceType("m1.large")
|
||||||
|
.monitoringState(MonitoringState.PENDING).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testConvertWhenNotOpenReturnsNull() {
|
||||||
|
|
||||||
|
assertEquals(new SpotInstanceRequestToAWSRunningInstance().apply(SpotInstanceRequest.builder()
|
||||||
|
.region("us-east-1").id("sir-228e6406").type(SpotInstanceRequest.Type.ONE_TIME).state(
|
||||||
|
SpotInstanceRequest.State.ACTIVE).build()), null);
|
||||||
|
|
||||||
|
assertEquals(new SpotInstanceRequestToAWSRunningInstance().apply(SpotInstanceRequest.builder()
|
||||||
|
.region("us-east-1").id("sir-228e6406").type(SpotInstanceRequest.Type.ONE_TIME).state(
|
||||||
|
SpotInstanceRequest.State.CANCELLED).build()), null);
|
||||||
|
|
||||||
|
assertEquals(new SpotInstanceRequestToAWSRunningInstance().apply(SpotInstanceRequest.builder()
|
||||||
|
.region("us-east-1").id("sir-228e6406").type(SpotInstanceRequest.Type.ONE_TIME).state(
|
||||||
|
SpotInstanceRequest.State.UNRECOGNIZED).build()), null);
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,6 +41,7 @@ import org.jclouds.Constants;
|
||||||
import org.jclouds.aws.domain.Region;
|
import org.jclouds.aws.domain.Region;
|
||||||
import org.jclouds.aws.ec2.AWSEC2AsyncClient;
|
import org.jclouds.aws.ec2.AWSEC2AsyncClient;
|
||||||
import org.jclouds.aws.ec2.AWSEC2Client;
|
import org.jclouds.aws.ec2.AWSEC2Client;
|
||||||
|
import org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions;
|
||||||
import org.jclouds.aws.ec2.domain.AWSRunningInstance;
|
import org.jclouds.aws.ec2.domain.AWSRunningInstance;
|
||||||
import org.jclouds.compute.ComputeServiceContext;
|
import org.jclouds.compute.ComputeServiceContext;
|
||||||
import org.jclouds.compute.ComputeServiceContextFactory;
|
import org.jclouds.compute.ComputeServiceContextFactory;
|
||||||
|
@ -49,10 +50,7 @@ import org.jclouds.compute.domain.ExecResponse;
|
||||||
import org.jclouds.compute.domain.NodeMetadata;
|
import org.jclouds.compute.domain.NodeMetadata;
|
||||||
import org.jclouds.compute.options.TemplateOptions;
|
import org.jclouds.compute.options.TemplateOptions;
|
||||||
import org.jclouds.domain.Credentials;
|
import org.jclouds.domain.Credentials;
|
||||||
import org.jclouds.ec2.EC2Client;
|
|
||||||
import org.jclouds.ec2.domain.KeyPair;
|
import org.jclouds.ec2.domain.KeyPair;
|
||||||
import org.jclouds.ec2.domain.RunningInstance;
|
|
||||||
import org.jclouds.ec2.services.InstanceClient;
|
|
||||||
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
|
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
|
||||||
import org.jclouds.rest.RestContext;
|
import org.jclouds.rest.RestContext;
|
||||||
import org.jclouds.ssh.jsch.config.JschSshClientModule;
|
import org.jclouds.ssh.jsch.config.JschSshClientModule;
|
||||||
|
@ -106,8 +104,8 @@ public class AWSKeyPairClientLiveTest {
|
||||||
public void setupClient() {
|
public void setupClient() {
|
||||||
setupCredentials();
|
setupCredentials();
|
||||||
Properties overrides = setupProperties();
|
Properties overrides = setupProperties();
|
||||||
computeContext = new ComputeServiceContextFactory().createContext(provider,
|
computeContext = new ComputeServiceContextFactory().createContext(provider, ImmutableSet.<Module> of(
|
||||||
ImmutableSet.<Module> of(new Log4JLoggingModule(), new JschSshClientModule()), overrides);
|
new Log4JLoggingModule(), new JschSshClientModule()), overrides);
|
||||||
context = computeContext.getProviderSpecificContext();
|
context = computeContext.getProviderSpecificContext();
|
||||||
client = context.getApi().getKeyPairServices();
|
client = context.getApi().getKeyPairServices();
|
||||||
}
|
}
|
||||||
|
@ -116,19 +114,19 @@ public class AWSKeyPairClientLiveTest {
|
||||||
|
|
||||||
Map<String, String> keyPair = ComputeTestUtils.setupKeyPair();
|
Map<String, String> keyPair = ComputeTestUtils.setupKeyPair();
|
||||||
|
|
||||||
InstanceClient instanceClient = EC2Client.class.cast(context.getApi()).getInstanceServices();
|
AWSInstanceClient instanceClient = AWSEC2Client.class.cast(context.getApi()).getInstanceServices();
|
||||||
|
|
||||||
String group = PREFIX + "unssh";
|
String group = PREFIX + "unssh";
|
||||||
computeContext.getComputeService().destroyNodesMatching(inGroup(group));
|
computeContext.getComputeService().destroyNodesMatching(inGroup(group));
|
||||||
|
|
||||||
TemplateOptions options = computeContext.getComputeService().templateOptions();
|
TemplateOptions options = computeContext.getComputeService().templateOptions();
|
||||||
|
|
||||||
options.authorizePublicKey(keyPair.get("public"));
|
options.authorizePublicKey(keyPair.get("public")).as(AWSEC2TemplateOptions.class).spotPrice(0.3f);
|
||||||
|
|
||||||
ComputeServiceContext noSshContext = null;
|
ComputeServiceContext noSshContext = null;
|
||||||
try {
|
try {
|
||||||
noSshContext = new ComputeServiceContextFactory().createContext(provider,
|
noSshContext = new ComputeServiceContextFactory().createContext(provider, ImmutableSet
|
||||||
ImmutableSet.of(new Log4JLoggingModule()), setupProperties());
|
.of(new Log4JLoggingModule()), setupProperties());
|
||||||
|
|
||||||
Set<? extends NodeMetadata> nodes = noSshContext.getComputeService().createNodesInGroup(group, 1, options);
|
Set<? extends NodeMetadata> nodes = noSshContext.getComputeService().createNodesInGroup(group, 1, options);
|
||||||
|
|
||||||
|
@ -136,9 +134,9 @@ public class AWSKeyPairClientLiveTest {
|
||||||
assert first.getCredentials() != null : first;
|
assert first.getCredentials() != null : first;
|
||||||
assert first.getCredentials().identity != null : first;
|
assert first.getCredentials().identity != null : first;
|
||||||
|
|
||||||
AWSRunningInstance instance = AWSRunningInstance.class
|
AWSRunningInstance instance = getInstance(instanceClient, first.getProviderId());
|
||||||
.cast(getInstance(instanceClient, first.getProviderId()));
|
|
||||||
|
|
||||||
|
assert instance.getSpotInstanceRequestId() != null : instance;
|
||||||
assertEquals(instance.getKeyName(), "jclouds#" + group);
|
assertEquals(instance.getKeyName(), "jclouds#" + group);
|
||||||
assertEquals(first.getCredentials().credential, null);
|
assertEquals(first.getCredentials().credential, null);
|
||||||
|
|
||||||
|
@ -146,7 +144,8 @@ public class AWSKeyPairClientLiveTest {
|
||||||
.runScriptOnNodesMatching(
|
.runScriptOnNodesMatching(
|
||||||
runningInGroup(group),
|
runningInGroup(group),
|
||||||
exec("echo hello"),
|
exec("echo hello"),
|
||||||
overrideCredentialsWith(new Credentials(first.getCredentials().identity, keyPair.get("private")))
|
overrideCredentialsWith(
|
||||||
|
new Credentials(first.getCredentials().identity, keyPair.get("private")))
|
||||||
.wrapInInitScript(false).runAsRoot(false));
|
.wrapInInitScript(false).runAsRoot(false));
|
||||||
|
|
||||||
ExecResponse hello = getOnlyElement(responses.values());
|
ExecResponse hello = getOnlyElement(responses.values());
|
||||||
|
@ -235,9 +234,8 @@ public class AWSKeyPairClientLiveTest {
|
||||||
assertEquals(listPair.getKeyFingerprint(), keyPair.getKeyFingerprint());
|
assertEquals(listPair.getKeyFingerprint(), keyPair.getKeyFingerprint());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected RunningInstance getInstance(InstanceClient instanceClient, String id) {
|
protected AWSRunningInstance getInstance(AWSInstanceClient instanceClient, String id) {
|
||||||
RunningInstance instance = getOnlyElement(getOnlyElement(instanceClient.describeInstancesInRegion(null, id)));
|
return getOnlyElement(getOnlyElement(instanceClient.describeInstancesInRegion(null, id)));
|
||||||
return instance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterTest
|
@AfterTest
|
||||||
|
|
Loading…
Reference in New Issue