Merge pull request #1133 from jclouds/ec2-tagapi

moved off deprecated TagClient -> TagApi
This commit is contained in:
Adrian Cole 2013-01-01 20:10:02 -08:00
commit 1be4fbd993
50 changed files with 1188 additions and 1613 deletions

View File

@ -25,6 +25,7 @@ import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
import static org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_DELIMITER;
import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_AMI_OWNERS;
import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_AUTO_ALLOCATE_ELASTIC_IPS;
import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_GENERATE_INSTANCE_NAMES;
import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_TIMEOUT_SECURITYGROUP_PRESENT;
import java.net.URI;
@ -88,6 +89,7 @@ public class EC2ApiMetadata extends BaseRestApiMetadata {
properties.setProperty(PROPERTY_EC2_TIMEOUT_SECURITYGROUP_PRESENT, "500");
properties.setProperty(PROPERTY_EC2_AUTO_ALLOCATE_ELASTIC_IPS, "false");
properties.setProperty(RESOURCENAME_DELIMITER, "#");
properties.setProperty(PROPERTY_EC2_GENERATE_INSTANCE_NAMES, "true");
return properties;
}

View File

@ -24,11 +24,15 @@ import static org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_D
import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING;
import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED;
import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED;
import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromValuesOfEmptyString;
import static org.jclouds.compute.util.ComputeServiceUtils.metadataAndTagsAsValuesOfEmptyString;
import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_GENERATE_INSTANCE_NAMES;
import static org.jclouds.ec2.util.Tags.resourceToTagsAsMap;
import static org.jclouds.util.Preconditions2.checkNotEmpty;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicReference;
@ -41,10 +45,13 @@ import org.jclouds.Constants;
import org.jclouds.aws.util.AWSUtils;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.extensions.ImageExtension;
import org.jclouds.compute.functions.GroupNamingConvention;
@ -70,6 +77,8 @@ import org.jclouds.ec2.compute.domain.RegionNameAndIngressRules;
import org.jclouds.ec2.compute.options.EC2TemplateOptions;
import org.jclouds.ec2.domain.KeyPair;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.ec2.domain.Tag;
import org.jclouds.ec2.util.TagFilterBuilder;
import org.jclouds.predicates.Retryables;
import org.jclouds.scriptbuilder.functions.InitAdminAccess;
@ -79,9 +88,13 @@ import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableMultimap.Builder;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.inject.Inject;
/**
@ -89,10 +102,11 @@ import com.google.inject.Inject;
*/
@Singleton
public class EC2ComputeService extends BaseComputeService {
private final EC2Client ec2Client;
private final EC2Client client;
private final ConcurrentMap<RegionAndName, KeyPair> credentialsMap;
private final LoadingCache<RegionAndName, String> securityGroupMap;
private final Factory namingConvention;
private final boolean generateInstanceNames;
@Inject
protected EC2ComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore,
@ -109,19 +123,74 @@ public class EC2ComputeService extends BaseComputeService {
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, EC2Client ec2Client,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, EC2Client client,
ConcurrentMap<RegionAndName, KeyPair> credentialsMap,
@Named("SECURITY") LoadingCache<RegionAndName, String> securityGroupMap,
Optional<ImageExtension> imageExtension, GroupNamingConvention.Factory namingConvention) {
Optional<ImageExtension> imageExtension, GroupNamingConvention.Factory namingConvention,
@Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean generateInstanceNames) {
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getImageStrategy,
getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy,
startNodeStrategy, stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning,
nodeTerminated, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory,
persistNodeCredentials, timeouts, executor, imageExtension);
this.ec2Client = ec2Client;
this.client = client;
this.credentialsMap = credentialsMap;
this.securityGroupMap = securityGroupMap;
this.namingConvention = namingConvention;
this.generateInstanceNames = generateInstanceNames;
}
@Override
public Set<? extends NodeMetadata> createNodesInGroup(String group, int count, final Template template)
throws RunNodesException {
Set<? extends NodeMetadata> nodes = super.createNodesInGroup(group, count, template);
String region = AWSUtils.getRegionFromLocationOrNull(template.getLocation());
if (client.getTagApiForRegion(region).isPresent()) {
Map<String, String> common = metadataAndTagsAsValuesOfEmptyString(template.getOptions());
if (common.size() > 0 || generateInstanceNames) {
return addTagsToInstancesInRegion(common, nodes, region, group);
}
}
return nodes;
}
private static final Function<NodeMetadata, String> instanceId = new Function<NodeMetadata, String>() {
@Override
public String apply(NodeMetadata in) {
return in.getProviderId();
}
};
private Set<NodeMetadata> addTagsToInstancesInRegion(Map<String, String> common, Set<? extends NodeMetadata> input,
String region, String group) {
Map<String, ? extends NodeMetadata> instancesById = Maps.uniqueIndex(input, instanceId);
ImmutableSet.Builder<NodeMetadata> builder = ImmutableSet.<NodeMetadata> builder();
if (generateInstanceNames && !common.containsKey("Name")) {
for (String id : instancesById.keySet()) {
Map<String, String> tags = ImmutableMap.<String, String> builder().putAll(common)
.put("Name", id.replaceAll(".*-", group + "-")).build();
logger.debug(">> applying tags %s to instance %s in region %s", tags, id, region);
client.getTagApiForRegion(region).get().applyToResources(tags, ImmutableSet.of(id));
builder.add(addTagsForInstance(tags, instancesById.get(id)));
}
} else {
Iterable<String> ids = instancesById.keySet();
logger.debug(">> applying tags %s to instances %s in region %s", common, ids, region);
client.getTagApiForRegion(region).get().applyToResources(common, ids);
for (NodeMetadata in : input)
builder.add(addTagsForInstance(common, in));
}
if (logger.isDebugEnabled()) {
Multimap<String, String> filter = new TagFilterBuilder().resourceIds(instancesById.keySet()).build();
FluentIterable<Tag> tags = client.getTagApiForRegion(region).get().filter(filter);
logger.debug("<< applied tags in region %s: %s", region, resourceToTagsAsMap(tags));
}
return builder.build();
}
private static NodeMetadata addTagsForInstance(Map<String, String> tags, NodeMetadata input) {
NodeMetadataBuilder builder = NodeMetadataBuilder.fromNodeMetadata(input).name(tags.get("Name"));
return addMetadataAndParseTagsFromValuesOfEmptyString(builder, tags).build();
}
@Inject(optional = true)
@ -137,9 +206,9 @@ public class EC2ComputeService extends BaseComputeService {
checkNotEmpty(group, "group");
String groupName = namingConvention.create().sharedNameForGroup(group);
if (ec2Client.getSecurityGroupServices().describeSecurityGroupsInRegion(region, groupName).size() > 0) {
if (client.getSecurityGroupServices().describeSecurityGroupsInRegion(region, groupName).size() > 0) {
logger.debug(">> deleting securityGroup(%s)", groupName);
ec2Client.getSecurityGroupServices().deleteSecurityGroupInRegion(region, groupName);
client.getSecurityGroupServices().deleteSecurityGroupInRegion(region, groupName);
// TODO: test this clear happens
securityGroupMap.invalidate(new RegionNameAndIngressRules(region, groupName, null, false));
logger.debug("<< deleted securityGroup(%s)", groupName);
@ -148,20 +217,20 @@ public class EC2ComputeService extends BaseComputeService {
@VisibleForTesting
void deleteKeyPair(String region, String group) {
for (KeyPair keyPair : ec2Client.getKeyPairServices().describeKeyPairsInRegion(region)) {
for (KeyPair keyPair : client.getKeyPairServices().describeKeyPairsInRegion(region)) {
String keyName = keyPair.getKeyName();
Predicate<String> keyNameMatcher = namingConvention.create().containsGroup(group);
String oldKeyNameRegex = String.format("jclouds#%s#%s#%s", group, region, "[0-9a-f]+").replace('#', delimiter);
// old keypair pattern too verbose as it has an unnecessary region qualifier
if (keyNameMatcher.apply(keyName) || keyName.matches(oldKeyNameRegex)) {
Set<String> instancesUsingKeyPair = extractIdsFromInstances(filter(concat(ec2Client.getInstanceServices()
Set<String> instancesUsingKeyPair = extractIdsFromInstances(filter(concat(client.getInstanceServices()
.describeInstancesInRegion(region)), usingKeyPairAndNotDead(keyPair)));
if (instancesUsingKeyPair.size() > 0) {
logger.debug("<< inUse keyPair(%s), by (%s)", keyPair.getKeyName(), instancesUsingKeyPair);
} else {
logger.debug(">> deleting keyPair(%s)", keyPair.getKeyName());
ec2Client.getKeyPairServices().deleteKeyPairInRegion(region, keyPair.getKeyName());
client.getKeyPairServices().deleteKeyPairInRegion(region, keyPair.getKeyName());
// TODO: test this clear happens
credentialsMap.remove(new RegionAndName(region, keyPair.getKeyName()));
credentialsMap.remove(new RegionAndName(region, group));
@ -184,7 +253,6 @@ public class EC2ComputeService extends BaseComputeService {
protected Predicate<RunningInstance> usingKeyPairAndNotDead(final KeyPair keyPair) {
return new Predicate<RunningInstance>() {
@Override
public boolean apply(RunningInstance input) {
switch (input.getInstanceState()) {
@ -194,7 +262,6 @@ public class EC2ComputeService extends BaseComputeService {
}
return keyPair.getKeyName().equals(input.getKeyName());
}
};
}

View File

@ -18,26 +18,33 @@
*/
package org.jclouds.ec2.compute.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
/**
*
* @author Adrian Cole
*/
public class RegionAndName {
protected final String region;
protected final String name;
public RegionAndName(String region, String name) {
this.region = region;
this.name = name;
public String slashEncode() {
return new StringBuilder(region).append('/').append(name).toString();
}
public RegionAndName(String region, String name) {
this.region = checkNotNull(region, "region");
this.name = checkNotNull(name, "name");
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((region == null) ? 0 : region.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
return Objects.hashCode(region, name);
}
@Override
@ -46,20 +53,10 @@ public class RegionAndName {
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
if (!(obj instanceof RegionAndName))
return false;
RegionAndName other = (RegionAndName) obj;
if (region == null) {
if (other.region != null)
return false;
} else if (!region.equals(other.region))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
RegionAndName other = RegionAndName.class.cast(obj);
return Objects.equal(region, other.region) && Objects.equal(name, other.name);
}
public String getRegion() {
@ -72,7 +69,45 @@ public class RegionAndName {
@Override
public String toString() {
return "[region=" + region + ", name=" + name + "]";
return string().toString();
}
protected ToStringHelper string() {
return Objects.toStringHelper("").add("region", region).add("name", name);
}
private static enum RegionFunction implements Function<RegionAndName, String> {
INSTANCE;
@Override
public String apply(RegionAndName input) {
return input.getRegion();
}
@Override
public String toString() {
return "getRegion()";
}
};
public static Function<RegionAndName, String> regionFunction() {
return RegionFunction.INSTANCE;
}
private static enum NameFunction implements Function<RegionAndName, String> {
INSTANCE;
@Override
public String apply(RegionAndName input) {
return input.getName();
}
@Override
public String toString() {
return "getName()";
}
};
public static Function<RegionAndName, String> nameFunction() {
return NameFunction.INSTANCE;
}
}

View File

@ -0,0 +1,84 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.ec2.compute.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.toArray;
import static com.google.common.collect.Multimaps.index;
import static com.google.common.collect.Multimaps.transformValues;
import static org.jclouds.ec2.compute.domain.RegionAndName.nameFunction;
import static org.jclouds.ec2.compute.domain.RegionAndName.regionFunction;
import java.util.Collection;
import java.util.Set;
import javax.annotation.Resource;
import javax.inject.Singleton;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.collect.Multimap;
import com.google.inject.Inject;
/**
* returns the instances present in the list. Makes a single rest call per aggregate on region.
*
* @author Adrian Cole
*/
@Singleton
public class PresentInstances implements Function<Set<RegionAndName>, Set<RunningInstance>> {
@Resource
protected Logger logger = Logger.NULL;
private final EC2Client client;
@Inject
public PresentInstances(EC2Client client) {
this.client = checkNotNull(client, "client");
}
@Override
public Set<RunningInstance> apply(Set<RegionAndName> regionAndIds) {
if (checkNotNull(regionAndIds, "regionAndIds").isEmpty())
return ImmutableSet.of();
Builder<RunningInstance> builder = ImmutableSet.<RunningInstance> builder();
Multimap<String, String> regionToInstanceIds = transformValues(index(regionAndIds, regionFunction()),
nameFunction());
for (String region : regionToInstanceIds.keySet()) {
Collection<String> instanceIds = regionToInstanceIds.get(region);
logger.trace("looking for instances %s in region %s", instanceIds, region);
builder.addAll(concat(client.getInstanceServices().describeInstancesInRegion(region,
toArray(instanceIds, String.class))));
}
return builder.build();
}
@Override
public String toString(){
return "presentInstances()";
}
}

View File

@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.not;
import static com.google.common.base.Strings.emptyToNull;
import static com.google.common.collect.Iterables.filter;
import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromValuesOfEmptyString;
import java.util.List;
import java.util.Map;
@ -101,11 +102,8 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
if (instance == null || instance.getId() == null)
return null;
NodeMetadataBuilder builder = new NodeMetadataBuilder();
builder = buildInstance(instance, builder);
return builder.build();
}
protected NodeMetadataBuilder buildInstance(final RunningInstance instance, NodeMetadataBuilder builder) {
builder.name(instance.getTags().get("Name"));
addMetadataAndParseTagsFromValuesOfEmptyString(builder, instance.getTags());
builder.providerId(instance.getId());
builder.id(instance.getRegion() + "/" + instance.getId());
String group = getGroupForInstance(instance);
@ -145,7 +143,7 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
} catch (UncheckedExecutionException e) {
logger.debug("error getting image for %s: %s", regionAndName, e);
}
return builder;
return builder.build();
}
protected void addCredentialsForInstance(NodeMetadataBuilder builder, RunningInstance instance) {

View File

@ -42,6 +42,7 @@ import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.hash.Hashing;
import com.google.common.primitives.Bytes;
/**
@ -119,7 +120,8 @@ public class EC2TemplateOptions extends TemplateOptions implements Cloneable {
if (noKeyPair)
toString.add("noKeyPair", noKeyPair);
toString.add("keyPair", keyPair);
toString.add("userData", userData);
if (userData != null && userData.size() > 0)
toString.add("userDataCksum", Hashing.crc32().hashBytes(Bytes.toArray(userData)));
ImmutableSet<BlockDeviceMapping> mappings = blockDeviceMappings.build();
if (mappings.size() != 0)
toString.add("blockDeviceMappings", mappings);

View File

@ -1,70 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.ec2.compute.predicates;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.NoSuchElementException;
import javax.annotation.Resource;
import javax.inject.Singleton;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.logging.Logger;
import org.jclouds.rest.ResourceNotFoundException;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.inject.Inject;
/**
*
* @author Adrian Cole
*/
@Singleton
public class InstancePresent implements Predicate<RegionAndName> {
private final EC2Client client;
@Resource
protected Logger logger = Logger.NULL;
@Inject
public InstancePresent(EC2Client client) {
this.client = checkNotNull(client, "client");
}
public boolean apply(RegionAndName instance) {
logger.trace("looking for instance %s/%s", instance.getRegion(), instance.getName());
try {
refresh(instance);
return true;
} catch (ResourceNotFoundException e) {
return false;
} catch (NoSuchElementException e) {
return false;
}
}
protected void refresh(RegionAndName instance) {
Iterables.getOnlyElement(Iterables.getOnlyElement(client.getInstanceServices().describeInstancesInRegion(
instance.getRegion(), instance.getName())));
}
}

View File

@ -17,9 +17,13 @@
* under the License.
*/
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.concat;
import static com.google.common.collect.Iterables.size;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Sets.difference;
import static com.google.common.util.concurrent.Atomics.newReference;
import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING;
import static org.jclouds.compute.functions.DefaultCredentialsFromImageOrOverridingCredentials.overrideDefaultCredentialsWithOptionsIfPresent;
import static org.jclouds.ec2.compute.util.EC2ComputeUtils.getZoneFromLocationOrNull;
@ -32,14 +36,12 @@ import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.aws.util.AWSUtils;
import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.strategy.CreateNodesInGroupThenAddToSet;
@ -48,7 +50,7 @@ import org.jclouds.domain.Credentials;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.compute.predicates.InstancePresent;
import org.jclouds.ec2.compute.functions.PresentInstances;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.ec2.options.RunInstancesOptions;
import org.jclouds.ec2.reference.EC2Constants;
@ -56,14 +58,12 @@ import org.jclouds.logging.Logger;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.util.concurrent.Atomics;
/**
* creates futures that correlate to
@ -94,30 +94,26 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
final Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata;
@VisibleForTesting
final ComputeUtils utils;
final InstancePresent instancePresent;
final PresentInstances presentInstances;
final LoadingCache<RunningInstance, LoginCredentials> instanceToCredentials;
final Map<String, Credentials> credentialStore;
final Provider<TemplateBuilder> templateBuilderProvider;
@Inject
protected EC2CreateNodesInGroupThenAddToSet(
EC2Client client,
@Named("ELASTICIP")
LoadingCache<RegionAndName, String> elasticIpCache,
@Named(TIMEOUT_NODE_RUNNING) Predicate<AtomicReference<NodeMetadata>> nodeRunning,
Provider<TemplateBuilder> templateBuilderProvider,
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
InstancePresent instancePresent, Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
LoadingCache<RunningInstance, LoginCredentials> instanceToCredentials, Map<String, Credentials> credentialStore,
ComputeUtils utils) {
EC2Client client,
@Named("ELASTICIP") LoadingCache<RegionAndName, String> elasticIpCache,
@Named(TIMEOUT_NODE_RUNNING) Predicate<AtomicReference<NodeMetadata>> nodeRunning,
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
PresentInstances presentInstances, Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
LoadingCache<RunningInstance, LoginCredentials> instanceToCredentials,
Map<String, Credentials> credentialStore, ComputeUtils utils) {
this.client = checkNotNull(client, "client");
this.elasticIpCache = checkNotNull(elasticIpCache, "elasticIpCache");
this.nodeRunning = checkNotNull(nodeRunning, "nodeRunning");
this.templateBuilderProvider = checkNotNull(templateBuilderProvider, "templateBuilderProvider");
this.instancePresent = checkNotNull(instancePresent, "instancePresent");
this.presentInstances = checkNotNull(presentInstances, "presentInstances");
this.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = checkNotNull(
createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
"createKeyPairAndSecurityGroupsAsNeededAndReturncustomize");
createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
"createKeyPairAndSecurityGroupsAsNeededAndReturncustomize");
this.runningInstanceToNodeMetadata = checkNotNull(runningInstanceToNodeMetadata, "runningInstanceToNodeMetadata");
this.instanceToCredentials = checkNotNull(instanceToCredentials, "instanceToCredentials");
this.credentialStore = checkNotNull(credentialStore, "credentialStore");
@ -133,109 +129,111 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
@Override
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) {
Template mutableTemplate = template.clone();
Iterable<String> ips = allocateElasticIpsInRegion(count, mutableTemplate);
Iterable<? extends RunningInstance> started = createKeyPairAndSecurityGroupsAsNeededThenRunInstances(group,
count, mutableTemplate);
Iterable<RegionAndName> ids = transform(started, instanceToRegionAndName);
String idsString = Joiner.on(',').join(ids);
if (Iterables.size(ids) > 0) {
logger.debug("<< started instances(%s)", idsString);
all(ids, instancePresent);
logger.debug("<< present instances(%s)", idsString);
populateCredentials(started, template.getOptions());
Set<RunningInstance> started = runInstancesAndWarnOnInvisible(group, count, mutableTemplate);
if (started.size() == 0) {
logger.warn("<< unable to start instances(%s)", mutableTemplate);
return ImmutableMap.of();
}
assignElasticIpsToInstances(ips, started);
return utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(mutableTemplate.getOptions(), transform(started,
runningInstanceToNodeMetadata), goodNodes, badNodes, customizationResponses);
populateCredentials(started, template.getOptions());
if (autoAllocateElasticIps) // before customization as the elastic ips may be needed
blockUntilRunningAndAssignElasticIpsToInstancesOrPutIntoBadMap(started, badNodes);
return utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(mutableTemplate.getOptions(),
transform(started, runningInstanceToNodeMetadata), goodNodes, badNodes, customizationResponses);
}
protected void populateCredentials(Iterable<? extends RunningInstance> started, TemplateOptions options) {
/**
* attempts to start the specified count of instances. eventual consistency might cause a problem where instances
* aren't immediately visible to the api. This method will warn when that occurs.
*/
private Set<RunningInstance> runInstancesAndWarnOnInvisible(String group, int count, Template mutableTemplate) {
Set<RunningInstance> started = createKeyPairAndSecurityGroupsAsNeededThenRunInstances(group, count,
mutableTemplate);
Set<RegionAndName> startedIds = ImmutableSet.copyOf(transform(started, instanceToRegionAndName));
if (startedIds.size() == 0) {
return ImmutableSet.copyOf(started);
}
logger.debug("<< started instances(%s)", startedIds);
Set<RunningInstance> visible = presentInstances.apply(startedIds);
Set<RegionAndName> visibleIds = ImmutableSet.copyOf(transform(visible, instanceToRegionAndName));
logger.trace("<< visible instances(%s)", visibleIds);
// add an exception for each of the nodes we cannot customize
Set<RegionAndName> invisibleIds = difference(startedIds, visibleIds);
if (invisibleIds.size() > 0) {
logger.warn("<< not api visible instances(%s)", invisibleIds);
}
return started;
}
private void populateCredentials(Set<RunningInstance> input, TemplateOptions options) {
LoginCredentials credentials = null;
for (RunningInstance instance : started) {
for (RunningInstance instance : input) {
credentials = instanceToCredentials.apply(instance);
if (credentials != null)
break;
}
credentials = overrideDefaultCredentialsWithOptionsIfPresent(credentials, options);
if (credentials != null)
for (RunningInstance instance : started)
credentialStore.put("node#" + instance.getRegion() + "/" + instance.getId(), credentials);
for (RegionAndName instance : transform(input, instanceToRegionAndName))
credentialStore.put("node#" + instance.slashEncode(), credentials);
}
protected Iterable<String> allocateElasticIpsInRegion(int count, Template template) {
Builder<String> ips = ImmutableSet.builder();
if (!autoAllocateElasticIps)
return ips.build();
String region = AWSUtils.getRegionFromLocationOrNull(template.getLocation());
logger.debug("<< allocating %d elastic IPs for nodes in region (%s)", count, region);
for (int i = 0; i < count; ++i) {
ips.add(client.getElasticIPAddressServices().allocateAddressInRegion(region));
}
return ips.build();
}
protected void assignElasticIpsToInstances(Iterable<String> ips, Iterable<? extends RunningInstance> startedInstances) {
if (!autoAllocateElasticIps)
return;
// TODO parallel
int i = 0;
for (RunningInstance startedInstance : startedInstances) {
String ip = Iterables.get(ips, i);
String region = startedInstance.getRegion();
String id = startedInstance.getId();
RegionAndName coordinates = new RegionAndName(region, id);
// block until instance is running
logger.debug(">> awaiting status running instance(%s)", coordinates);
AtomicReference<NodeMetadata> node = Atomics.newReference(runningInstanceToNodeMetadata.apply(startedInstance));
nodeRunning.apply(node);
logger.trace("<< running instance(%s)", coordinates);
logger.debug(">> associating elastic IP %s to instance %s", ip, coordinates);
client.getElasticIPAddressServices().associateAddressInRegion(region, ip, id);
logger.trace("<< associated elastic IP %s to instance %s", ip, coordinates);
// add mapping of instance to ip into the cache
elasticIpCache.put(coordinates, ip);
private void blockUntilRunningAndAssignElasticIpsToInstancesOrPutIntoBadMap(Set<RunningInstance> input,
Map<NodeMetadata, Exception> badNodes) {
Map<RegionAndName, RunningInstance> instancesById = Maps.uniqueIndex(input, instanceToRegionAndName);
for (RegionAndName id : instancesById.keySet()) {
try {
logger.debug("<< allocating elastic IP instance(%s)", id);
String ip = client.getElasticIPAddressServices().allocateAddressInRegion(id.getRegion());
// block until instance is running
logger.debug(">> awaiting status running instance(%s)", id);
AtomicReference<NodeMetadata> node = newReference(runningInstanceToNodeMetadata
.apply(instancesById.get(id)));
nodeRunning.apply(node);
logger.trace("<< running instance(%s)", id);
logger.debug(">> associating elastic IP %s to instance %s", ip, id);
client.getElasticIPAddressServices().associateAddressInRegion(id.getRegion(), ip, id.getName());
logger.trace("<< associated elastic IP %s to instance %s", ip, id);
// add mapping of instance to ip into the cache
elasticIpCache.put(id, ip);
} catch (RuntimeException e) {
badNodes.put(runningInstanceToNodeMetadata.apply(instancesById.get(id)), e);
}
}
}
protected Iterable<? extends RunningInstance> createKeyPairAndSecurityGroupsAsNeededThenRunInstances(String group,
int count, Template template) {
private Set<RunningInstance> createKeyPairAndSecurityGroupsAsNeededThenRunInstances(String group, int count,
Template template) {
String region = AWSUtils.getRegionFromLocationOrNull(template.getLocation());
String zone = getZoneFromLocationOrNull(template.getLocation());
RunInstancesOptions instanceOptions = createKeyPairAndSecurityGroupsAsNeededAndReturncustomize.execute(region,
group, template);
group, template);
return createNodesInRegionAndZone(region, zone, group, count, template, instanceOptions);
}
protected Iterable<? extends RunningInstance> createNodesInRegionAndZone(String region, String zone, String group,
int count, Template template, RunInstancesOptions instanceOptions) {
protected Set<RunningInstance> createNodesInRegionAndZone(String region, String zone, String group, int count,
Template template, RunInstancesOptions instanceOptions) {
int countStarted = 0;
int tries = 0;
Iterable<? extends RunningInstance> started = ImmutableSet.<RunningInstance> of();
Set<RunningInstance> started = ImmutableSet.<RunningInstance> of();
while (countStarted < count && tries++ < count) {
if (logger.isDebugEnabled())
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, client.getInstanceServices().runInstancesInRegion(region, zone,
template.getImage().getProviderId(), 1, count - countStarted, instanceOptions));
started = ImmutableSet.copyOf(concat(
started,
client.getInstanceServices().runInstancesInRegion(region, zone, template.getImage().getProviderId(), 1,
count - countStarted, instanceOptions)));
countStarted = Iterables.size(started);
countStarted = size(started);
if (countStarted < count)
logger.debug(">> not enough instances (%d/%d) started, attempting again", countStarted, count);
}

View File

@ -28,6 +28,7 @@ import org.jclouds.javax.annotation.Nullable;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.base.Strings;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@ -42,11 +43,18 @@ import com.google.common.collect.Sets;
* @author Adrian Cole
*/
public class RunningInstance implements Comparable<RunningInstance> {
public static Builder builder() {
return new Builder();
public static Builder<?> builder() {
return new ConcreteBuilder();
}
public static class Builder {
public Builder<?> toBuilder() {
return new ConcreteBuilder().fromRunningInstance(this);
}
public abstract static class Builder<T extends Builder<T>> {
protected abstract T self();
protected String region;
protected Set<String> groupNames = Sets.newLinkedHashSet();
protected String amiLaunchIndex;
@ -70,157 +78,174 @@ public class RunningInstance implements Comparable<RunningInstance> {
protected RootDeviceType rootDeviceType = RootDeviceType.INSTANCE_STORE;
protected String rootDeviceName;
protected Map<String, BlockDevice> ebsBlockDevices = Maps.newLinkedHashMap();
protected Map<String, String> tags = Maps.newLinkedHashMap();
public Builder region(String region) {
public T tags(Map<String, String> tags) {
this.tags = ImmutableMap.copyOf(checkNotNull(tags, "tags"));
return self();
}
public T tag(String key, String value) {
if (key != null)
this.tags.put(key, Strings.nullToEmpty(value));
return self();
}
public T region(String region) {
this.region = region;
return this;
return self();
}
public Builder groupNames(Iterable<String> groupNames) {
public T groupNames(Iterable<String> groupNames) {
this.groupNames = ImmutableSet.copyOf(checkNotNull(groupNames, "groupNames"));
return this;
return self();
}
public Builder groupName(String groupName) {
public T groupName(String groupName) {
if (groupName != null)
this.groupNames.add(groupName);
return this;
return self();
}
public Builder amiLaunchIndex(String amiLaunchIndex) {
public T amiLaunchIndex(String amiLaunchIndex) {
this.amiLaunchIndex = amiLaunchIndex;
return this;
return self();
}
public Builder dnsName(String dnsName) {
public T dnsName(String dnsName) {
this.dnsName = dnsName;
return this;
return self();
}
public Builder imageId(String imageId) {
public T imageId(String imageId) {
this.imageId = imageId;
return this;
return self();
}
public Builder instanceId(String instanceId) {
public T instanceId(String instanceId) {
this.instanceId = instanceId;
return this;
return self();
}
public Builder instanceState(InstanceState instanceState) {
public T instanceState(InstanceState instanceState) {
this.instanceState = instanceState;
return this;
return self();
}
public Builder rawState(String rawState) {
public T rawState(String rawState) {
this.rawState = rawState;
return this;
return self();
}
public Builder instanceType(String instanceType) {
public T instanceType(String instanceType) {
this.instanceType = instanceType;
return this;
return self();
}
public Builder ipAddress(String ipAddress) {
public T ipAddress(String ipAddress) {
this.ipAddress = ipAddress;
return this;
return self();
}
public Builder kernelId(String kernelId) {
public T kernelId(String kernelId) {
this.kernelId = kernelId;
return this;
return self();
}
public Builder keyName(String keyName) {
public T keyName(String keyName) {
this.keyName = keyName;
return this;
return self();
}
public Builder launchTime(Date launchTime) {
public T launchTime(Date launchTime) {
this.launchTime = launchTime;
return this;
return self();
}
public Builder availabilityZone(String availabilityZone) {
public T availabilityZone(String availabilityZone) {
this.availabilityZone = availabilityZone;
return this;
return self();
}
public Builder virtualizationType(String virtualizationType) {
public T virtualizationType(String virtualizationType) {
this.virtualizationType = virtualizationType;
return this;
return self();
}
public Builder platform(String platform) {
public T platform(String platform) {
this.platform = platform;
return this;
return self();
}
public Builder privateDnsName(String privateDnsName) {
public T privateDnsName(String privateDnsName) {
this.privateDnsName = privateDnsName;
return this;
return self();
}
public Builder privateIpAddress(String privateIpAddress) {
public T privateIpAddress(String privateIpAddress) {
this.privateIpAddress = privateIpAddress;
return this;
return self();
}
public Builder ramdiskId(String ramdiskId) {
public T ramdiskId(String ramdiskId) {
this.ramdiskId = ramdiskId;
return this;
return self();
}
public Builder reason(String reason) {
public T reason(String reason) {
this.reason = reason;
return this;
return self();
}
public Builder rootDeviceType(RootDeviceType rootDeviceType) {
public T rootDeviceType(RootDeviceType rootDeviceType) {
this.rootDeviceType = rootDeviceType;
return this;
return self();
}
public Builder rootDeviceName(String rootDeviceName) {
public T rootDeviceName(String rootDeviceName) {
this.rootDeviceName = rootDeviceName;
return this;
return self();
}
public Builder devices(Map<String, BlockDevice> ebsBlockDevices) {
public T devices(Map<String, BlockDevice> ebsBlockDevices) {
this.ebsBlockDevices = ImmutableMap.copyOf(checkNotNull(ebsBlockDevices, "ebsBlockDevices"));
return this;
return self();
}
public Builder device(String key, BlockDevice value) {
public T device(String key, BlockDevice value) {
if (key != null && value != null)
this.ebsBlockDevices.put(key, value);
return self();
}
public T fromRunningInstance(RunningInstance in) {
return region(in.region).groupNames(in.groupNames).amiLaunchIndex(in.amiLaunchIndex).dnsName(in.dnsName)
.imageId(in.imageId).instanceId(in.instanceId).instanceState(in.instanceState).rawState(in.rawState)
.instanceType(in.instanceType).ipAddress(in.ipAddress).kernelId(in.kernelId).keyName(in.keyName)
.launchTime(in.launchTime).availabilityZone(in.availabilityZone)
.virtualizationType(in.virtualizationType).platform(in.platform).privateDnsName(in.privateDnsName)
.privateIpAddress(in.privateIpAddress).ramdiskId(in.ramdiskId).reason(in.reason)
.rootDeviceType(in.rootDeviceType).rootDeviceName(in.rootDeviceName).devices(in.ebsBlockDevices)
.tags(in.tags);
}
public abstract RunningInstance build();
}
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
@Override
protected ConcreteBuilder self() {
return this;
}
@Override
public RunningInstance build() {
return new RunningInstance(region, groupNames, amiLaunchIndex, dnsName, imageId, instanceId, instanceState,
rawState, instanceType, ipAddress, kernelId, keyName, launchTime, availabilityZone,
virtualizationType, platform, privateDnsName, privateIpAddress, ramdiskId, reason, rootDeviceType,
rootDeviceName, ebsBlockDevices);
rawState, instanceType, ipAddress, kernelId, keyName, launchTime, availabilityZone, virtualizationType,
platform, privateDnsName, privateIpAddress, ramdiskId, reason, rootDeviceType, rootDeviceName,
ebsBlockDevices, tags);
}
public String getDnsName() {
return dnsName;
}
public String getIpAddress() {
return ipAddress;
}
public String getPrivateDnsName() {
return privateDnsName;
}
public String getPrivateIpAddress() {
return privateIpAddress;
}
}
protected final String region;
@ -256,6 +281,7 @@ public class RunningInstance implements Comparable<RunningInstance> {
@Nullable
protected final String rootDeviceName;
protected final Map<String, BlockDevice> ebsBlockDevices;
protected final Map<String, String> tags;
protected RunningInstance(String region, Iterable<String> groupNames, @Nullable String amiLaunchIndex,
@Nullable String dnsName, String imageId, String instanceId, InstanceState instanceState, String rawState,
@ -263,7 +289,7 @@ public class RunningInstance implements Comparable<RunningInstance> {
Date launchTime, String availabilityZone, String virtualizationType, @Nullable String platform,
@Nullable String privateDnsName, @Nullable String privateIpAddress, @Nullable String ramdiskId,
@Nullable String reason, RootDeviceType rootDeviceType, @Nullable String rootDeviceName,
Map<String, BlockDevice> ebsBlockDevices) {
Map<String, BlockDevice> ebsBlockDevices, Map<String, String> tags) {
this.region = checkNotNull(region, "region");
this.amiLaunchIndex = amiLaunchIndex; // nullable on runinstances.
this.dnsName = dnsName; // nullable on runinstances.
@ -287,6 +313,7 @@ public class RunningInstance implements Comparable<RunningInstance> {
this.rootDeviceName = rootDeviceName;
this.ebsBlockDevices = ImmutableMap.copyOf(checkNotNull(ebsBlockDevices, "ebsBlockDevices for %s/%s", region, instanceId));
this.groupNames = ImmutableSet.copyOf(checkNotNull(groupNames, "groupNames for %s/%s", region, instanceId));
this.tags = ImmutableMap.<String, String> copyOf(checkNotNull(tags, "tags"));
}
/**
@ -462,6 +489,13 @@ public class RunningInstance implements Comparable<RunningInstance> {
return groupNames;
}
/**
* tags that are present in the instance
*/
public Map<String, String> getTags() {
return tags;
}
@Override
public int compareTo(RunningInstance other) {
return ComparisonChain.start().compare(region, other.region).compare(instanceId, other.instanceId, Ordering.natural().nullsLast()).result();
@ -489,7 +523,7 @@ public class RunningInstance implements Comparable<RunningInstance> {
.add("ipAddress", ipAddress).add("dnsName", dnsName).add("privateIpAddress", privateIpAddress)
.add("privateDnsName", privateDnsName).add("keyName", keyName).add("groupNames", groupNames)
.add("platform", platform).add("launchTime", launchTime).add("rootDeviceName", rootDeviceName)
.add("rootDeviceType", rootDeviceType).add("ebsBlockDevices", ebsBlockDevices);
.add("rootDeviceType", rootDeviceType).add("ebsBlockDevices", ebsBlockDevices).add("tags", tags);
}
@Override

View File

@ -18,6 +18,8 @@
*/
package org.jclouds.ec2.reference;
import org.jclouds.compute.ComputeService;
/**
* Configuration properties and constants used in EC2 connections.
*
@ -40,4 +42,11 @@ public interface EC2Constants {
* deallocate when the node is destroyed.
*/
public static final String PROPERTY_EC2_AUTO_ALLOCATE_ELASTIC_IPS = "jclouds.ec2.auto-allocate-elastic-ips";
/**
* If this property is set to true(default), jclouds generate a name for each instance based on the group. ex.
* i-ef34ae2 becomes hadoop-ef34ae2. Note that this depends on {@link EC2Api#getTagApi} returning present.
*/
public static final String PROPERTY_EC2_GENERATE_INSTANCE_NAMES = "jclouds.ec2.generate-instance-names";
}

View File

@ -0,0 +1,103 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.ec2.util;
import static com.google.common.collect.Multimaps.index;
import java.util.Map;
import org.jclouds.ec2.domain.Tag;
import com.google.common.base.Function;
import com.google.common.collect.Maps;
/**
*
* @author Adrian Cole
*/
public class Tags {
private Tags() {
}
/**
* maps the input on {@link Tag#getResourceId()} with a value of a map of its {@link Tag#getKey()} to
* {@link Tag#getValue()}
*/
public static Map<String, Map<String, String>> resourceToTagsAsMap(Iterable<Tag> tags) {
return Maps.transformValues(index(tags, resourceIdFunction()).asMap(),
new Function<Iterable<Tag>, Map<String, String>>() {
@Override
public Map<String, String> apply(Iterable<Tag> in) {
return Maps.transformValues(Maps.uniqueIndex(in, keyFunction()), valueFunction());
}
});
}
public static enum ValueFunction implements Function<Tag, String> {
INSTANCE;
@Override
public String apply(Tag in) {
return in.getValue().or("");
}
@Override
public String toString() {
return "getValue()";
}
}
public static Function<Tag, String> valueFunction() {
return ValueFunction.INSTANCE;
}
public static enum KeyFunction implements Function<Tag, String> {
INSTANCE;
@Override
public String apply(Tag in) {
return in.getKey();
}
@Override
public String toString() {
return "getKey()";
}
}
public static Function<Tag, String> keyFunction() {
return KeyFunction.INSTANCE;
}
public static enum ResourceIdFunction implements Function<Tag, String> {
INSTANCE;
@Override
public String apply(Tag in) {
return in.getResourceId();
}
@Override
public String toString() {
return "getResourceId()";
}
}
public static Function<Tag, String> resourceIdFunction() {
return ResourceIdFunction.INSTANCE;
}
}

View File

@ -42,7 +42,6 @@ import org.xml.sax.Attributes;
import com.google.common.base.Supplier;
import com.google.common.collect.Sets;
import com.google.inject.Provider;
/**
*
@ -52,21 +51,28 @@ public abstract class BaseReservationHandler<T> extends HandlerForGeneratedReque
protected final DateCodec dateCodec;
protected final Supplier<String> defaultRegion;
protected final Provider<Builder> builderProvider;
@Inject
public BaseReservationHandler(DateCodecFactory dateCodecFactory, @Region Supplier<String> defaultRegion,
Provider<RunningInstance.Builder> builderProvider) {
public BaseReservationHandler(DateCodecFactory dateCodecFactory, @Region Supplier<String> defaultRegion) {
this.dateCodec = dateCodecFactory.iso8601();
this.defaultRegion = defaultRegion;
this.builderProvider = builderProvider;
this.builder = builderProvider.get();
}
protected Builder<?> builder = newBuilder();
protected Builder<?> newBuilder() {
return RunningInstance.builder();
}
protected void inItem() {
if (endOfInstanceItem()) {
refineBuilderBeforeAddingInstance();
instances.add(builder.build());
builder = newBuilder();
}
}
protected StringBuilder currentText = new StringBuilder();
protected Builder builder;
protected int itemDepth;
protected boolean inInstancesSet;
protected boolean inProductCodes;
@ -181,13 +187,6 @@ public abstract class BaseReservationHandler<T> extends HandlerForGeneratedReque
currentText = new StringBuilder();
}
protected void inItem() {
if (endOfInstanceItem()) {
refineBuilderBeforeAddingInstance();
instances.add(builder.build());
builder = builderProvider.get();
}
}
protected void refineBuilderBeforeAddingInstance() {
String region = getRequest() != null ? AWSUtils.findRegionInArgsOrNull(getRequest()) : null;
@ -195,10 +194,6 @@ public abstract class BaseReservationHandler<T> extends HandlerForGeneratedReque
builder.groupNames(groupNames);
}
protected Builder builder() {
return builder;
}
protected boolean endOfInstanceItem() {
return itemDepth <= 2 && inInstancesSet && !inProductCodes && !inGroupSet;
}

View File

@ -18,6 +18,8 @@
*/
package org.jclouds.ec2.xml;
import static org.jclouds.util.SaxUtils.equalsOrSuffix;
import java.util.Set;
import javax.inject.Inject;
@ -26,10 +28,11 @@ import org.jclouds.date.DateCodecFactory;
import org.jclouds.ec2.domain.Reservation;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.location.Region;
import org.xml.sax.Attributes;
import com.google.common.base.Supplier;
import com.google.common.collect.Sets;
import com.google.inject.Provider;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
/**
* Parses the following XML document:
@ -40,18 +43,53 @@ import com.google.inject.Provider;
* @see <a href="http: />
*/
public class DescribeInstancesResponseHandler extends
BaseReservationHandler<Set<Reservation<? extends RunningInstance>>> {
private Set<Reservation<? extends RunningInstance>> reservations = Sets.newLinkedHashSet();
BaseReservationHandler<Set<Reservation<? extends RunningInstance>>> {
private final TagSetHandler tagSetHandler;
private Builder<Reservation<? extends RunningInstance>> reservations = ImmutableSet
.<Reservation<? extends RunningInstance>> builder();
private boolean inTagSet;
@Inject
public DescribeInstancesResponseHandler(DateCodecFactory dateCodecFactory,
@Region Supplier<String> defaultRegion, Provider<RunningInstance.Builder> builderProvider) {
super(dateCodecFactory, defaultRegion, builderProvider);
DescribeInstancesResponseHandler(DateCodecFactory dateCodecFactory, @Region Supplier<String> defaultRegion,
TagSetHandler tagSetHandler) {
super(dateCodecFactory, defaultRegion);
this.tagSetHandler = tagSetHandler;
}
@Override
public void startElement(String uri, String name, String qName, Attributes attrs) {
super.startElement(uri, name, qName, attrs);
if (equalsOrSuffix(qName, "tagSet")) {
inTagSet = true;
}
if (inTagSet) {
tagSetHandler.startElement(uri, name, qName, attrs);
}
}
@Override
public void characters(char ch[], int start, int length) {
if (inTagSet) {
tagSetHandler.characters(ch, start, length);
} else {
super.characters(ch, start, length);
}
}
@Override
public void endElement(String uri, String name, String qName) {
if (equalsOrSuffix(qName, "tagSet")) {
inTagSet = false;
builder.tags(tagSetHandler.getResult());
} else if (inTagSet) {
tagSetHandler.endElement(uri, name, qName);
}
super.endElement(uri, name, qName);
}
@Override
public Set<Reservation<? extends RunningInstance>> getResult() {
return reservations;
return reservations.build();
}
protected boolean endOfReservationItem() {
@ -67,4 +105,7 @@ public class DescribeInstancesResponseHandler extends
}
}
protected boolean endOfInstanceItem() {
return itemDepth == 2 && inInstancesSet;
}
}

View File

@ -26,7 +26,6 @@ import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.location.Region;
import com.google.common.base.Supplier;
import com.google.inject.Provider;
/**
* Parses the following XML document:
@ -39,9 +38,8 @@ import com.google.inject.Provider;
public class RunInstancesResponseHandler extends BaseReservationHandler<Reservation<? extends RunningInstance>> {
@Inject
public RunInstancesResponseHandler(DateCodecFactory dateCodecFactory, @Region Supplier<String> defaultRegion,
Provider<RunningInstance.Builder> builderProvider) {
super(dateCodecFactory, defaultRegion, builderProvider);
public RunInstancesResponseHandler(DateCodecFactory dateCodecFactory, @Region Supplier<String> defaultRegion) {
super(dateCodecFactory, defaultRegion);
}
@Override

View File

@ -0,0 +1,80 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.ec2.xml;
import static org.jclouds.util.SaxUtils.currentOrNull;
import static org.jclouds.util.SaxUtils.equalsOrSuffix;
import java.util.Map;
import org.jclouds.http.functions.ParseSax;
import org.xml.sax.Attributes;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
/**
* @author grkvlt@apache.org
*/
public class TagSetHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Map<String, String>> {
private StringBuilder currentText = new StringBuilder();
private ImmutableMap.Builder<String, String> result;
private boolean inItem = false;
private String key;
private String value;
public Map<String, String> getResult() {
return result.build();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) {
if (equalsOrSuffix(qName, "tagSet")) {
result = ImmutableMap.builder();
} else if (qName.equals("item")) {
inItem = true;
key = null;
value = null;
}
currentText = new StringBuilder();
}
@Override
public void endElement(String uri, String localName, String qName) {
if (qName.equals("item")) {
inItem = false;
if (key != null) {
result.put(key, Strings.nullToEmpty(value));
}
}
if (inItem) {
if (qName.equals("key")) {
key = currentOrNull(currentText);
} else if (qName.equals("value")) {
value = currentOrNull(currentText);
}
}
}
@Override
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
}

View File

@ -85,13 +85,14 @@ public class EC2ComputeServiceLiveTest extends BaseComputeServiceLiveTest {
return new SshjSshClientModule();
}
// normal ec2 does not support metadata
@Override
protected void checkUserMetadataContains(NodeMetadata node, ImmutableMap<String, String> userMetadata) {
assert node.getUserMetadata().equals(ImmutableMap.<String, String> of()) : String.format(
"node userMetadata did not match %s %s", userMetadata, node);
if (view.unwrap(EC2ApiMetadata.CONTEXT_TOKEN).getApi().getTagApi().isPresent()) {
super.checkUserMetadataContains(node, userMetadata);
} else {
assertTrue(node.getUserMetadata().isEmpty(), "not expecting metadata when tag extension isn't present" + node);
}
}
@Test(enabled = true, dependsOnMethods = "testCorrectAuthException")
public void testImagesResolveCorrectly() {
@ -324,7 +325,7 @@ public class EC2ComputeServiceLiveTest extends BaseComputeServiceLiveTest {
return instance;
}
public static void cleanupExtendedStuffInRegion(String region, SecurityGroupClient securityGroupClient,
protected static void cleanupExtendedStuffInRegion(String region, SecurityGroupClient securityGroupClient,
KeyPairClient keyPairClient, String group) throws InterruptedException {
try {
for (SecurityGroup secgroup : securityGroupClient.describeSecurityGroupsInRegion(region))

View File

@ -0,0 +1,70 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.ec2.compute.functions;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.testng.Assert.assertEquals;
import java.util.Set;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.domain.Reservation;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.ec2.services.InstanceClient;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
/**
* @author Adrian Cole
*/
@Test(groups = "unit")
public class PresentInstancesTest {
RunningInstance instance1 = createMock(RunningInstance.class);
RunningInstance instance2 = createMock(RunningInstance.class);
@SuppressWarnings("unchecked")
@Test
public void testWhenInstancesPresentSingleCall() {
EC2Client client = createMock(EC2Client.class);
InstanceClient instanceClient = createMock(InstanceClient.class);
expect(client.getInstanceServices()).andReturn(instanceClient);
// avoid imatcher fail. if you change this, be sure to check multiple jres
expect(instanceClient.describeInstancesInRegion("us-east-1", "i-aaaa", "i-bbbb")).andReturn(
Set.class.cast(ImmutableSet.of(Reservation.builder().region("us-east-1")
.instances(ImmutableSet.of(instance1, instance2)).build())));
replay(client, instanceClient);
PresentInstances fn = new PresentInstances(client);
assertEquals(fn.apply(ImmutableSet.of(new RegionAndName("us-east-1", "i-aaaa"), new RegionAndName("us-east-1",
"i-bbbb"))), ImmutableSet.of(instance1, instance2));
verify(client, instanceClient);
}
}

View File

@ -36,7 +36,6 @@ import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadata.Status;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.predicates.AtomicNodeRunning;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import org.jclouds.compute.util.ComputeUtils;
@ -47,9 +46,9 @@ import org.jclouds.domain.LocationScope;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.compute.functions.PresentInstances;
import org.jclouds.ec2.compute.functions.RunningInstanceToNodeMetadata;
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.RunningInstance;
import org.jclouds.ec2.options.RunInstancesOptions;
@ -62,7 +61,6 @@ import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import com.google.inject.util.Providers;
/**
* @author Adrian Cole
@ -81,8 +79,7 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
NodeMetadata nodeMetadata = new NodeMetadataBuilder().id(region + "/" + instanceCreatedId)
.providerId(instanceCreatedId).status(Status.RUNNING).build();
// setup mocks
TemplateBuilder templateBuilder = createMock(TemplateBuilder.class);
EC2CreateNodesInGroupThenAddToSet strategy = setupStrategy(templateBuilder, nodeMetadata);
EC2CreateNodesInGroupThenAddToSet strategy = setupStrategy(nodeMetadata);
InputParams input = new InputParams(location);
InstanceClient instanceClient = createMock(InstanceClient.class);
ElasticIPAddressClient ipClient = createMock(ElasticIPAddressClient.class);
@ -122,7 +119,7 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
expect(instance.getRegion()).andReturn(region).atLeastOnce();
expect(strategy.credentialStore.put("node#" + region + "/" + instanceCreatedId, creds)).andReturn(null);
expect(strategy.instancePresent.apply(new RegionAndName(region, instanceCreatedId))).andReturn(true);
expect(strategy.presentInstances.apply(ImmutableSet.of(new RegionAndName(region, instanceCreatedId)))).andReturn(ImmutableSet.of(instance));
expect(input.template.getOptions()).andReturn(input.options).atLeastOnce();
expect(input.options.getLoginUser()).andReturn(null);
expect(input.options.getLoginPassword()).andReturn(null);
@ -135,7 +132,6 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
.andReturn(null);
// replay mocks
replay(templateBuilder);
replay(instanceClient);
replay(ipClient);
replay(ec2Options);
@ -147,7 +143,6 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
strategy.execute(input.tag, input.count, input.template, input.nodes, input.badNodes, input.customization);
// verify mocks
verify(templateBuilder);
verify(instanceClient);
verify(ipClient);
verify(ec2Options);
@ -195,8 +190,7 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
.providerId(instanceCreatedId).status(Status.RUNNING).build();
// setup mocks
TemplateBuilder templateBuilder = createMock(TemplateBuilder.class);
EC2CreateNodesInGroupThenAddToSet strategy = setupStrategy(templateBuilder, nodeMetadata);
EC2CreateNodesInGroupThenAddToSet strategy = setupStrategy(nodeMetadata);
InputParams input = new InputParams(location);
InstanceClient instanceClient = createMock(InstanceClient.class);
RunInstancesOptions ec2Options = createMock(RunInstancesOptions.class);
@ -223,7 +217,7 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
expect(instance.getRegion()).andReturn(region).atLeastOnce();
expect(strategy.credentialStore.put("node#" + region + "/" + instanceCreatedId, creds)).andReturn(null);
expect(strategy.instancePresent.apply(new RegionAndName(region, instanceCreatedId))).andReturn(true);
expect(strategy.presentInstances.apply(ImmutableSet.of(new RegionAndName(region, instanceCreatedId)))).andReturn(ImmutableSet.of(instance));
expect(input.template.getOptions()).andReturn(input.options).atLeastOnce();
expect(input.options.getLoginUser()).andReturn(null);
expect(input.options.getLoginPassword()).andReturn(null);
@ -238,7 +232,6 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
.andReturn(null);
// replay mocks
replay(templateBuilder);
replay(instanceClient);
replay(ec2Options);
replay(instance);
@ -249,7 +242,6 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
strategy.execute(input.tag, input.count, input.template, input.nodes, input.badNodes, input.customization);
// verify mocks
verify(templateBuilder);
verify(instanceClient);
verify(ec2Options);
verify(instance);
@ -307,7 +299,7 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
verify(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize);
verify(strategy.client);
verify(strategy.elasticIpCache);
verify(strategy.instancePresent);
verify(strategy.presentInstances);
verify(strategy.runningInstanceToNodeMetadata);
verify(strategy.instanceToCredentials);
verify(strategy.credentialStore);
@ -315,10 +307,10 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
}
@SuppressWarnings("unchecked")
private EC2CreateNodesInGroupThenAddToSet setupStrategy(TemplateBuilder template, final NodeMetadata node) {
private EC2CreateNodesInGroupThenAddToSet setupStrategy(final NodeMetadata node) {
EC2Client client = createMock(EC2Client.class);
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = createMock(CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.class);
InstancePresent instancePresent = createMock(InstancePresent.class);
PresentInstances presentInstances = createMock(PresentInstances.class);
RunningInstanceToNodeMetadata runningInstanceToNodeMetadata = createMock(RunningInstanceToNodeMetadata.class);
LoadingCache<RunningInstance, LoginCredentials> instanceToCredentials = createMock(LoadingCache.class);
LoadingCache<RegionAndName, String> elasticIpCache = createMock(LoadingCache.class);
@ -334,15 +326,15 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
Map<String, Credentials> credentialStore = createMock(Map.class);
ComputeUtils utils = createMock(ComputeUtils.class);
return new EC2CreateNodesInGroupThenAddToSet(client, elasticIpCache, new AtomicNodeRunning(nodeRunning),
Providers.<TemplateBuilder> of(template), createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
instancePresent, runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils);
createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, presentInstances, runningInstanceToNodeMetadata,
instanceToCredentials, credentialStore, utils);
}
private void replayStrategy(EC2CreateNodesInGroupThenAddToSet strategy) {
replay(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize);
replay(strategy.client);
replay(strategy.elasticIpCache);
replay(strategy.instancePresent);
replay(strategy.presentInstances);
replay(strategy.runningInstanceToNodeMetadata);
replay(strategy.instanceToCredentials);
replay(strategy.credentialStore);

View File

@ -0,0 +1,57 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.ec2.util;
import static org.jclouds.ec2.domain.Tag.ResourceType.IMAGE;
import static org.jclouds.ec2.domain.Tag.ResourceType.INSTANCE;
import static org.testng.Assert.assertEquals;
import org.jclouds.ec2.domain.Tag;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
/**
* @author Adrian Cole
*/
@Test
public class TagsTest {
Tag resourceTag1 = Tag.builder().resourceType(IMAGE).resourceId("1").key("key").value("value").build();
public void testValueFunction() {
assertEquals(Tags.valueFunction().apply(resourceTag1), "value");
}
public void testKeyFunction() {
assertEquals(Tags.keyFunction().apply(resourceTag1), "key");
}
Tag resourceTag2 = Tag.builder().resourceType(IMAGE).resourceId("1").key("foo").value("bar").build();
Tag resource2Tag1 = Tag.builder().resourceType(INSTANCE).resourceId("2").key("absent").build();
Tag resource2Tag2 = Tag.builder().resourceType(INSTANCE).resourceId("2").key("hello").value("world").build();
public void testResourceToTagsAsMap() {
assertEquals(
Tags.resourceToTagsAsMap(ImmutableSet.of(resourceTag1, resourceTag2, resource2Tag1, resource2Tag2)),
ImmutableMap.of("1", ImmutableMap.of("key", "value", "foo", "bar"),
"2", ImmutableMap.of("absent", "", "hello", "world")));
}
}

View File

@ -41,6 +41,7 @@ import org.testng.annotations.Test;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
@ -69,7 +70,7 @@ public class DescribeInstancesResponseHandlerTest extends BaseEC2HandlerTest {
public void testWhenRunning() throws UnknownHostException {
Set<Reservation<RunningInstance>> contents = ImmutableSet.of(new Reservation<RunningInstance>(defaultRegion,
ImmutableSet.of("adriancole.ec2ingress"), ImmutableSet.of(new RunningInstance.Builder().region(
ImmutableSet.of("adriancole.ec2ingress"), ImmutableSet.of(RunningInstance.builder().region(
defaultRegion).groupName("adriancole.ec2ingress").amiLaunchIndex("0").dnsName(
"ec2-174-129-81-68.compute-1.amazonaws.com").imageId("ami-82e4b5c7").instanceId("i-0799056f")
.instanceState(InstanceState.RUNNING).rawState("running").instanceType(InstanceType.M1_SMALL)
@ -91,7 +92,7 @@ public class DescribeInstancesResponseHandlerTest extends BaseEC2HandlerTest {
public void testApplyInputStream() {
Set<Reservation<RunningInstance>> contents = ImmutableSet.of(new Reservation<RunningInstance>(defaultRegion,
ImmutableSet.of("default"), ImmutableSet.of(new RunningInstance.Builder().region(defaultRegion).groupName(
ImmutableSet.of("default"), ImmutableSet.of(RunningInstance.builder().region(defaultRegion).groupName(
"default").amiLaunchIndex("23").dnsName("ec2-72-44-33-4.compute-1.amazonaws.com").imageId(
"ami-6ea54007").instanceId("i-28a64341").instanceState(InstanceState.RUNNING).rawState(
"running").instanceType(InstanceType.M1_LARGE).kernelId("aki-ba3adfd3").keyName(
@ -100,8 +101,9 @@ public class DescribeInstancesResponseHandlerTest extends BaseEC2HandlerTest {
.availabilityZone("us-east-1b").virtualizationType("paravirtual").privateDnsName(
"10-251-50-132.ec2.internal")// product codes
// ImmutableSet.of("774F4FF8")
.tags(ImmutableMap.of("Name","ec2-o", "Empty",""))
.ramdiskId("ari-badbad00").rootDeviceType(RootDeviceType.INSTANCE_STORE).build(),
new RunningInstance.Builder().region(defaultRegion).groupName("default").amiLaunchIndex("23")
RunningInstance.builder().region(defaultRegion).groupName("default").amiLaunchIndex("23")
.dnsName("ec2-72-44-33-6.compute-1.amazonaws.com").imageId("ami-6ea54007").instanceId(
"i-28a64435").instanceState(InstanceState.RUNNING).rawState("running")
.instanceType(InstanceType.M1_LARGE).kernelId("aki-ba3adfd3").keyName(
@ -125,7 +127,7 @@ public class DescribeInstancesResponseHandlerTest extends BaseEC2HandlerTest {
public void testEBS() throws UnknownHostException {
Set<Reservation<RunningInstance>> contents = ImmutableSet.of(new Reservation<RunningInstance>(defaultRegion,
ImmutableSet.of("adriancole.ec2ebsingress"), ImmutableSet.of(new RunningInstance.Builder().region(
ImmutableSet.of("adriancole.ec2ebsingress"), ImmutableSet.of(RunningInstance.builder().region(
defaultRegion).groupName("adriancole.ec2ebsingress").amiLaunchIndex("0").dnsName(
"ec2-75-101-203-146.compute-1.amazonaws.com").imageId("ami-849875ed").instanceId("i-e564438d")
.instanceState(InstanceState.RUNNING).rawState("running").instanceType(InstanceType.M1_SMALL)

View File

@ -65,19 +65,19 @@ public class RunInstancesResponseHandlerTest extends BaseEC2HandlerTest {
Reservation<? extends RunningInstance> expected = new Reservation<RunningInstance>(defaultRegion, ImmutableSet
.of("default"), ImmutableSet.of(
new RunningInstance.Builder().region(defaultRegion).groupName("default").amiLaunchIndex("0")
RunningInstance.builder().region(defaultRegion).groupName("default").amiLaunchIndex("0")
.imageId("ami-60a54009").instanceId("i-2ba64342").instanceState(InstanceState.PENDING).rawState(
"pending").instanceType(InstanceType.M1_SMALL).keyName("example-key-name").launchTime(
dateService.iso8601DateParse("2007-08-07T11:51:50.000Z"))// MonitoringState.ENABLED,
.availabilityZone("us-east-1b").build(),
new RunningInstance.Builder().region(defaultRegion).groupName("default").amiLaunchIndex("1")
RunningInstance.builder().region(defaultRegion).groupName("default").amiLaunchIndex("1")
.imageId("ami-60a54009").instanceId("i-2bc64242").instanceState(InstanceState.PENDING).rawState(
"pending").instanceType(InstanceType.M1_SMALL).keyName("example-key-name").launchTime(
dateService.iso8601DateParse("2007-08-07T11:51:50.000Z"))// MonitoringState.ENABLED,
.availabilityZone("us-east-1b").build(),
new RunningInstance.Builder().region(defaultRegion).groupName("default").amiLaunchIndex("2")
RunningInstance.builder().region(defaultRegion).groupName("default").amiLaunchIndex("2")
.imageId("ami-60a54009").instanceId("i-2be64332").instanceState(InstanceState.PENDING).rawState(
"pending").instanceType(InstanceType.M1_SMALL).keyName("example-key-name").launchTime(
dateService.iso8601DateParse("2007-08-07T11:51:50.000Z"))// MonitoringState.ENABLED,
@ -98,7 +98,7 @@ public class RunInstancesResponseHandlerTest extends BaseEC2HandlerTest {
Reservation<? extends RunningInstance> expected = new Reservation<RunningInstance>(defaultRegion, ImmutableSet
.of("jclouds#greenqloud-computeblock"), ImmutableSet.of(
new RunningInstance.Builder().region(defaultRegion).groupName("jclouds#greenqloud-computeblock").amiLaunchIndex("0")
RunningInstance.builder().region(defaultRegion).groupName("jclouds#greenqloud-computeblock").amiLaunchIndex("0")
.imageId("qmi-9ac92558").instanceId("i-01b0dac3").instanceState(InstanceState.PENDING).rawState(
"pending").instanceType(InstanceType.M1_SMALL).keyName("jclouds#greenqloud-computeblock#35")
.launchTime(dateService.iso8601DateParse("2012-06-15T19:06:35.000+00:00"))

View File

@ -38,6 +38,16 @@
<kernelId>aki-ba3adfd3</kernelId>
<ramdiskId>ari-badbad00</ramdiskId>
<hypervisor>xen</hypervisor>
<tagSet>
<item>
<key>Name</key>
<value>ec2-o</value>
</item>
<item>
<key>Empty</key>
<value />
</item>
</tagSet>
</item>
<item>
<instanceId>i-28a64435</instanceId>

View File

@ -21,7 +21,6 @@ package org.jclouds.aws.ec2;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_GENERATE_INSTANCE_NAMES;
import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_AMI_OWNERS;
import java.util.Properties;
@ -66,13 +65,11 @@ public class AWSEC2ApiMetadata extends EC2ApiMetadata {
Properties properties = EC2ApiMetadata.defaultProperties();
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", SECONDS.toMillis(90) + "");
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "SpotInstanceClient.describeSpotPriceHistoryInRegion", MINUTES.toMillis(2) + "");
properties.remove(PROPERTY_EC2_AMI_OWNERS);
// auth fail sometimes happens in EC2, as the rc.local script that injects the
// authorized key executes after ssh has started.
properties.setProperty("jclouds.ssh.max-retries", "7");
properties.setProperty("jclouds.ssh.retry-auth", "true");
properties.setProperty(PROPERTY_EC2_GENERATE_INSTANCE_NAMES, "true");
return properties;
}

View File

@ -25,7 +25,6 @@ import org.jclouds.aws.ec2.services.AWSSecurityGroupAsyncClient;
import org.jclouds.aws.ec2.services.MonitoringAsyncClient;
import org.jclouds.aws.ec2.services.PlacementGroupAsyncClient;
import org.jclouds.aws.ec2.services.SpotInstanceAsyncClient;
import org.jclouds.aws.ec2.services.TagAsyncClient;
import org.jclouds.ec2.EC2AsyncClient;
import org.jclouds.rest.annotations.Delegate;
@ -82,10 +81,4 @@ public interface AWSEC2AsyncClient extends EC2AsyncClient {
*/
@Delegate
SpotInstanceAsyncClient getSpotInstanceServices();
/**
* Provides asynchronous access to SpotInstance services.
*/
@Delegate
TagAsyncClient getTagServices();
}

View File

@ -25,7 +25,6 @@ import org.jclouds.aws.ec2.services.AWSSecurityGroupClient;
import org.jclouds.aws.ec2.services.MonitoringClient;
import org.jclouds.aws.ec2.services.PlacementGroupClient;
import org.jclouds.aws.ec2.services.SpotInstanceClient;
import org.jclouds.aws.ec2.services.TagClient;
import org.jclouds.ec2.EC2Client;
import org.jclouds.rest.annotations.Delegate;
@ -81,10 +80,4 @@ public interface AWSEC2Client extends EC2Client {
*/
@Delegate
SpotInstanceClient getSpotInstanceServices();
/**
* Provides synchronous access to Tag services.
*/
@Delegate
TagClient getTagServices();
}

View File

@ -18,13 +18,11 @@
*/
package org.jclouds.aws.ec2.compute;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.transform;
import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_GENERATE_INSTANCE_NAMES;
import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING;
import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED;
import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED;
import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_GENERATE_INSTANCE_NAMES;
import java.util.Map;
import java.util.Set;
@ -38,20 +36,15 @@ import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.aws.ec2.AWSEC2AsyncClient;
import org.jclouds.aws.ec2.AWSEC2Client;
import org.jclouds.aws.ec2.domain.PlacementGroup;
import org.jclouds.aws.ec2.domain.PlacementGroup.State;
import org.jclouds.aws.util.AWSUtils;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.extensions.ImageExtension;
import org.jclouds.compute.functions.GroupNamingConvention;
@ -71,20 +64,15 @@ import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.ec2.compute.EC2ComputeService;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.compute.options.EC2TemplateOptions;
import org.jclouds.ec2.domain.KeyPair;
import org.jclouds.scriptbuilder.functions.InitAdminAccess;
import org.jclouds.util.Preconditions2;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
/**
* @author Adrian Cole
@ -94,96 +82,39 @@ public class AWSEC2ComputeService extends EC2ComputeService {
private final LoadingCache<RegionAndName, String> placementGroupMap;
private final Predicate<PlacementGroup> placementGroupDeleted;
private final AWSEC2Client ec2Client;
private final AWSEC2AsyncClient aclient;
private final boolean generateInstanceNames;
private final AWSEC2Client client;
@Inject
protected AWSEC2ComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore,
@Memoized Supplier<Set<? extends Image>> images, @Memoized Supplier<Set<? extends Hardware>> sizes,
@Memoized Supplier<Set<? extends Location>> locations, ListNodesStrategy listNodesStrategy,
GetImageStrategy getImageStrategy, GetNodeMetadataStrategy getNodeMetadataStrategy,
CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, RebootNodeStrategy rebootNodeStrategy,
DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy startNodeStrategy,
SuspendNodeStrategy stopNodeStrategy, Provider<TemplateBuilder> templateBuilderProvider,
@Named("DEFAULT") Provider<TemplateOptions> templateOptionsProvider,
@Named(TIMEOUT_NODE_RUNNING) Predicate<AtomicReference<NodeMetadata>> nodeRunning,
@Named(TIMEOUT_NODE_TERMINATED) Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
@Named(TIMEOUT_NODE_SUSPENDED) Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, AWSEC2Client ec2Client,
ConcurrentMap<RegionAndName, KeyPair> credentialsMap,
@Named("SECURITY") LoadingCache<RegionAndName, String> securityGroupMap,
@Named("PLACEMENT") LoadingCache<RegionAndName, String> placementGroupMap,
@Named("DELETED") Predicate<PlacementGroup> placementGroupDeleted,
@Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean generateInstanceNames, AWSEC2AsyncClient aclient,
Optional<ImageExtension> imageExtension, GroupNamingConvention.Factory namingConvention) {
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getImageStrategy, getNodeMetadataStrategy,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy,
stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
nodeSuspended, initScriptRunnerFactory, runScriptOnNodeFactory, initAdminAccess, persistNodeCredentials,
timeouts, executor, ec2Client, credentialsMap, securityGroupMap, imageExtension, namingConvention);
this.ec2Client = ec2Client;
@Memoized Supplier<Set<? extends Image>> images, @Memoized Supplier<Set<? extends Hardware>> sizes,
@Memoized Supplier<Set<? extends Location>> locations, ListNodesStrategy listNodesStrategy,
GetImageStrategy getImageStrategy, GetNodeMetadataStrategy getNodeMetadataStrategy,
CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, RebootNodeStrategy rebootNodeStrategy,
DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy startNodeStrategy,
SuspendNodeStrategy stopNodeStrategy, Provider<TemplateBuilder> templateBuilderProvider,
@Named("DEFAULT") Provider<TemplateOptions> templateOptionsProvider,
@Named(TIMEOUT_NODE_RUNNING) Predicate<AtomicReference<NodeMetadata>> nodeRunning,
@Named(TIMEOUT_NODE_TERMINATED) Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
@Named(TIMEOUT_NODE_SUSPENDED) Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, AWSEC2Client client,
ConcurrentMap<RegionAndName, KeyPair> credentialsMap,
@Named("SECURITY") LoadingCache<RegionAndName, String> securityGroupMap,
@Named("PLACEMENT") LoadingCache<RegionAndName, String> placementGroupMap,
@Named("DELETED") Predicate<PlacementGroup> placementGroupDeleted, Optional<ImageExtension> imageExtension,
GroupNamingConvention.Factory namingConvention,
@Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean generateInstanceNames) {
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getImageStrategy,
getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy,
startNodeStrategy, stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning,
nodeTerminated, nodeSuspended, initScriptRunnerFactory, runScriptOnNodeFactory, initAdminAccess,
persistNodeCredentials, timeouts, executor, client, credentialsMap, securityGroupMap, imageExtension,
namingConvention, generateInstanceNames);
this.client = client;
this.placementGroupMap = placementGroupMap;
this.placementGroupDeleted = placementGroupDeleted;
this.generateInstanceNames = generateInstanceNames;
this.aclient = checkNotNull(aclient, "aclient");
}
@Override
public Set<? extends NodeMetadata> createNodesInGroup(String group, int count, final Template template)
throws RunNodesException {
Set<? extends NodeMetadata> nodes = super.createNodesInGroup(group, count, template);
// tags from spot requests do not propagate to running instances
// automatically
if (templateWasASpotRequestWithUserMetadata(template)) {
addTagsToNodesFromUserMetadataInTemplate(nodes, group, template);
nodes = addUserMetadataFromTemplateOptionsToNodes(template, group, nodes);
}
return nodes;
}
protected void addTagsToNodesFromUserMetadataInTemplate(Set<? extends NodeMetadata> nodes, String group,
final Template template) {
String region = AWSUtils.getRegionFromLocationOrNull(template.getLocation());
if (template.getOptions().getUserMetadata().size() > 0 || generateInstanceNames) {
for (String id : transform(nodes, new Function<NodeMetadata, String>() {
@Override
public String apply(NodeMetadata arg0) {
return arg0.getProviderId();
}
}))
aclient.getTagServices().createTagsInRegion(region, ImmutableSet.of(id),
metadataForId(id, group, template.getOptions().getUserMetadata()));
}
}
private Map<String, String> metadataForId(String id, String group, Map<String, String> metadata) {
return generateInstanceNames && !metadata.containsKey("Name") ? ImmutableMap.<String, String> builder().putAll(
metadata).put("Name", id.replaceAll(".*-", group + "-")).build() : metadata;
}
protected boolean templateWasASpotRequestWithUserMetadata(final Template template) {
return template.getOptions().getUserMetadata().size() > 0
&& AWSEC2TemplateOptions.class.cast(template.getOptions()).getSpotPrice() != null;
}
protected Set<? extends NodeMetadata> addUserMetadataFromTemplateOptionsToNodes(final Template template,
final String group, Set<? extends NodeMetadata> nodes) {
nodes = ImmutableSet.copyOf(Iterables.transform(nodes, new Function<NodeMetadata, NodeMetadata>() {
@Override
public NodeMetadata apply(NodeMetadata arg0) {
Map<String, String> md = metadataForId(arg0.getProviderId(), group, template.getOptions().getUserMetadata());
return NodeMetadataBuilder.fromNodeMetadata(arg0).name(md.get("Name")).userMetadata(md).build();
}
}));
return nodes;
}
@VisibleForTesting
@ -193,10 +124,10 @@ public class AWSEC2ComputeService extends EC2ComputeService {
// http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/index.html?using_cluster_computing.html
String placementGroup = String.format("jclouds#%s#%s", group, region);
try {
if (ec2Client.getPlacementGroupServices().describePlacementGroupsInRegion(region, placementGroup).size() > 0) {
if (client.getPlacementGroupServices().describePlacementGroupsInRegion(region, placementGroup).size() > 0) {
logger.debug(">> deleting placementGroup(%s)", placementGroup);
try {
ec2Client.getPlacementGroupServices().deletePlacementGroupInRegion(region, placementGroup);
client.getPlacementGroupServices().deletePlacementGroupInRegion(region, placementGroup);
checkState(placementGroupDeleted.apply(new PlacementGroup(region, placementGroup, "cluster",
State.PENDING)), String.format("placementGroup region(%s) name(%s) failed to delete", region,
placementGroup));
@ -218,11 +149,11 @@ public class AWSEC2ComputeService extends EC2ComputeService {
}
/**
* returns template options, except of type {@link EC2TemplateOptions}.
* returns template options, except of type {@link AWSEC2TemplateOptions}.
*/
@Override
public EC2TemplateOptions templateOptions() {
return EC2TemplateOptions.class.cast(super.templateOptions());
public AWSEC2TemplateOptions templateOptions() {
return AWSEC2TemplateOptions.class.cast(super.templateOptions());
}
}

View File

@ -30,7 +30,7 @@ import javax.inject.Singleton;
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.functions.PresentSpotRequestsAndInstances;
import org.jclouds.aws.ec2.compute.strategy.AWSEC2CreateNodesInGroupThenAddToSet;
import org.jclouds.aws.ec2.compute.strategy.AWSEC2DestroyNodeStrategy;
import org.jclouds.aws.ec2.compute.strategy.AWSEC2GetNodeMetadataStrategy;
@ -44,11 +44,11 @@ import org.jclouds.compute.extensions.ImageExtension;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.ec2.compute.config.EC2BindComputeStrategiesByClass;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.compute.functions.PresentInstances;
import org.jclouds.ec2.compute.functions.RunningInstanceToNodeMetadata;
import org.jclouds.ec2.compute.internal.EC2TemplateBuilderImpl;
import org.jclouds.ec2.compute.loaders.RegionAndIdToImage;
import org.jclouds.ec2.compute.options.EC2TemplateOptions;
import org.jclouds.ec2.compute.predicates.InstancePresent;
import org.jclouds.ec2.compute.strategy.CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions;
import org.jclouds.ec2.compute.strategy.EC2CreateNodesInGroupThenAddToSet;
import org.jclouds.ec2.compute.strategy.EC2DestroyNodeStrategy;
@ -92,7 +92,7 @@ public class AWSEC2ComputeServiceContextModule extends BaseComputeServiceContext
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(PresentInstances.class).to(PresentSpotRequestsAndInstances.class);
bind(EC2CreateNodesInGroupThenAddToSet.class).to(AWSEC2CreateNodesInGroupThenAddToSet.class);
bind(RunningInstanceToNodeMetadata.class).to(AWSRunningInstanceToNodeMetadata.class);
}
@ -100,7 +100,7 @@ public class AWSEC2ComputeServiceContextModule extends BaseComputeServiceContext
protected void installDependencies() {
install(new AWSEC2ComputeServiceDependenciesModule());
}
@Override
protected boolean shouldEagerlyParseImages(Injector injector) {
Map<String, String> queries = injector.getInstance(Key.get(new TypeLiteral<Map<String, String>>() {

View File

@ -18,8 +18,6 @@
*/
package org.jclouds.aws.ec2.compute.functions;
import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromValuesOfEmptyString;
import java.util.Map;
import java.util.Set;
@ -31,8 +29,8 @@ import org.jclouds.collect.Memoized;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.HardwareBuilder;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.NodeMetadata.Status;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.functions.GroupNamingConvention;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
@ -82,11 +80,4 @@ public class AWSRunningInstanceToNodeMetadata extends RunningInstanceToNodeMetad
return HardwareBuilder.fromHardware(in).hypervisor(awsInstance.getHypervisor().toString()).build();
}
@Override
protected NodeMetadataBuilder buildInstance(RunningInstance instance, NodeMetadataBuilder builder) {
AWSRunningInstance awsInstance = AWSRunningInstance.class.cast(instance);
builder.name(awsInstance.getTags().get("Name"));
addMetadataAndParseTagsFromValuesOfEmptyString(builder, awsInstance.getTags());
return super.buildInstance(instance, builder);
}
}

View File

@ -0,0 +1,96 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.aws.ec2.compute.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.compose;
import static com.google.common.base.Predicates.containsPattern;
import static com.google.common.collect.Iterables.any;
import static com.google.common.collect.Iterables.toArray;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Multimaps.index;
import static com.google.common.collect.Multimaps.transformValues;
import static org.jclouds.ec2.compute.domain.RegionAndName.nameFunction;
import static org.jclouds.ec2.compute.domain.RegionAndName.regionFunction;
import java.util.Collection;
import java.util.Set;
import javax.inject.Singleton;
import org.jclouds.aws.ec2.AWSEC2Client;
import org.jclouds.aws.ec2.domain.AWSRunningInstance;
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
import org.jclouds.aws.ec2.functions.SpotInstanceRequestToAWSRunningInstance;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.compute.functions.PresentInstances;
import org.jclouds.ec2.domain.RunningInstance;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.collect.Multimap;
import com.google.inject.Inject;
/**
* returns either the instances present in the list, or spot instances, if they ids start with {@code sir-}. Makes a
* single rest call per aggregate on region.
*
* @author Adrian Cole
*/
@Singleton
public class PresentSpotRequestsAndInstances extends PresentInstances {
private final AWSEC2Client client;
private final Function<SpotInstanceRequest, AWSRunningInstance> spotConverter;
@Inject
public PresentSpotRequestsAndInstances(AWSEC2Client client, Function<SpotInstanceRequest, AWSRunningInstance> spotConverter) {
super(client);
this.client = checkNotNull(client, "client");
this.spotConverter = checkNotNull(spotConverter, "spotConverter");
}
@Override
public Set<RunningInstance> apply(Set<RegionAndName> regionAndIds) {
if (checkNotNull(regionAndIds, "regionAndIds").isEmpty())
return ImmutableSet.of();
if (any(regionAndIds, compose(containsPattern("sir-"), nameFunction())))
return getSpots(regionAndIds);
return super.apply(regionAndIds);
}
protected Set<RunningInstance> getSpots(Set<RegionAndName> regionAndIds) {
Builder<RunningInstance> builder = ImmutableSet.<RunningInstance> builder();
Multimap<String, String> regionToSpotIds = transformValues(index(regionAndIds, regionFunction()), nameFunction());
for (String region : regionToSpotIds.keySet()) {
Collection<String> spotIds = regionToSpotIds.get(region);
logger.trace("looking for spots %s in region %s", spotIds, region);
builder.addAll(transform(
client.getSpotInstanceServices().describeSpotInstanceRequestsInRegion(region,
toArray(spotIds, String.class)), spotConverter));
}
return builder.build();
}
@Override
public String toString() {
return "presentSpotRequestsAndInstances()";
}
}

View File

@ -1,55 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.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()));
}
}

View File

@ -19,30 +19,27 @@
package org.jclouds.aws.ec2.compute.strategy;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.transform;
import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_GENERATE_INSTANCE_NAMES;
import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING;
import static org.jclouds.compute.util.ComputeServiceUtils.metadataAndTagsAsValuesOfEmptyString;
import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_GENERATE_INSTANCE_NAMES;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
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.AWSEC2AsyncClient;
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.compute.functions.PresentSpotRequestsAndInstances;
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;
@ -58,7 +55,6 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
/**
@ -70,39 +66,33 @@ public class AWSEC2CreateNodesInGroupThenAddToSet extends EC2CreateNodesInGroupT
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
private Logger logger = Logger.NULL;
@VisibleForTesting
final AWSEC2Client client;
final SpotInstanceRequestToAWSRunningInstance spotConverter;
final AWSEC2AsyncClient aclient;
final boolean generateInstanceNames;
private final AWSEC2Client client;
private final SpotInstanceRequestToAWSRunningInstance spotConverter;
@Inject
protected AWSEC2CreateNodesInGroupThenAddToSet(
AWSEC2Client client,
@Named("ELASTICIP") LoadingCache<RegionAndName, String> elasticIpCache,
@Named(TIMEOUT_NODE_RUNNING) Predicate<AtomicReference<NodeMetadata>> nodeRunning,
AWSEC2AsyncClient aclient,
@Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean generateInstanceNames,
Provider<TemplateBuilder> templateBuilderProvider,
CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
AWSEC2InstancePresent instancePresent,
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
LoadingCache<RunningInstance, LoginCredentials> instanceToCredentials, Map<String, Credentials> credentialStore,
ComputeUtils utils, SpotInstanceRequestToAWSRunningInstance spotConverter) {
super(client, elasticIpCache, nodeRunning, templateBuilderProvider, createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
instancePresent, runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils);
AWSEC2Client client,
@Named("ELASTICIP") LoadingCache<RegionAndName, String> elasticIpCache,
@Named(TIMEOUT_NODE_RUNNING) Predicate<AtomicReference<NodeMetadata>> nodeRunning,
@Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean generateInstanceNames,
CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
PresentSpotRequestsAndInstances instancePresent,
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
LoadingCache<RunningInstance, LoginCredentials> instanceToCredentials,
Map<String, Credentials> credentialStore, ComputeUtils utils,
SpotInstanceRequestToAWSRunningInstance spotConverter) {
super(client, elasticIpCache, nodeRunning, createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
instancePresent, runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils);
this.client = checkNotNull(client, "client");
this.aclient = checkNotNull(aclient, "aclient");
this.spotConverter = checkNotNull(spotConverter, "spotConverter");
this.generateInstanceNames = generateInstanceNames;
}
@Override
protected Iterable<? extends RunningInstance> createNodesInRegionAndZone(String region, String zone, String group,
protected Set<RunningInstance> createNodesInRegionAndZone(String region, String zone, String group,
int count, Template template, RunInstancesOptions instanceOptions) {
Map<String, String> tags = metadataAndTagsAsValuesOfEmptyString(template.getOptions());
Float spotPrice = getSpotPriceOrNull(template.getOptions());
if (spotPrice != null) {
LaunchSpecification spec = AWSRunInstancesOptions.class.cast(instanceOptions).getLaunchSpecificationBuilder()
@ -111,38 +101,12 @@ public class AWSEC2CreateNodesInGroupThenAddToSet extends EC2CreateNodesInGroupT
if (logger.isDebugEnabled())
logger.debug(">> requesting %d spot instances region(%s) price(%f) spec(%s) options(%s)", count, region,
spotPrice, spec, options);
return addTagsToInstancesInRegion(tags, transform(client
.getSpotInstanceServices().requestSpotInstancesInRegion(region, spotPrice, count, spec, options),
spotConverter), region, group);
} else {
return addTagsToInstancesInRegion(tags, super.createNodesInRegionAndZone(
region, zone, group, count, template, instanceOptions), region, group);
return ImmutableSet.<RunningInstance> copyOf(transform(client.getSpotInstanceServices()
.requestSpotInstancesInRegion(region, spotPrice, count, spec, options), spotConverter));
}
return super.createNodesInRegionAndZone(region, zone, group, count, template, instanceOptions);
}
public Iterable<? extends RunningInstance> addTagsToInstancesInRegion(Map<String, String> metadata,
Iterable<? extends RunningInstance> iterable, String region, String group) {
if (metadata.size() > 0 || generateInstanceNames) {
for (String id : transform(iterable, new Function<RunningInstance, String>() {
@Override
public String apply(RunningInstance arg0) {
return arg0.getId();
}
}))
aclient.getTagServices()
.createTagsInRegion(region, ImmutableSet.of(id), metadataForId(id, group, metadata));
}
return iterable;
}
private Map<String, String> metadataForId(String id, String group, Map<String, String> metadata) {
return generateInstanceNames && !metadata.containsKey("Name") ? ImmutableMap.<String, String> builder().putAll(
metadata).put("Name", id.replaceAll(".*-", group + "-")).build() : metadata;
}
private Float getSpotPriceOrNull(TemplateOptions options) {
return options instanceof AWSEC2TemplateOptions ? AWSEC2TemplateOptions.class.cast(options).getSpotPrice() : null;
}

View File

@ -25,6 +25,8 @@ import javax.inject.Singleton;
import org.jclouds.aws.ec2.AWSEC2AsyncClient;
import org.jclouds.aws.ec2.AWSEC2Client;
import org.jclouds.aws.ec2.domain.AWSRunningInstance;
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
import org.jclouds.aws.ec2.functions.SpotInstanceRequestToAWSRunningInstance;
import org.jclouds.aws.ec2.options.AWSRunInstancesOptions;
import org.jclouds.aws.ec2.services.AWSAMIAsyncClient;
import org.jclouds.aws.ec2.services.AWSAMIClient;
@ -40,12 +42,9 @@ import org.jclouds.aws.ec2.services.PlacementGroupAsyncClient;
import org.jclouds.aws.ec2.services.PlacementGroupClient;
import org.jclouds.aws.ec2.services.SpotInstanceAsyncClient;
import org.jclouds.aws.ec2.services.SpotInstanceClient;
import org.jclouds.aws.ec2.services.TagAsyncClient;
import org.jclouds.aws.ec2.services.TagClient;
import org.jclouds.ec2.EC2AsyncClient;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.config.EC2RestClientModule;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.ec2.features.TagApi;
import org.jclouds.ec2.features.TagAsyncApi;
import org.jclouds.ec2.features.WindowsApi;
@ -67,9 +66,11 @@ import org.jclouds.ec2.services.WindowsAsyncClient;
import org.jclouds.ec2.services.WindowsClient;
import org.jclouds.rest.ConfiguresRestClient;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableMap;
import com.google.common.reflect.TypeToken;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
/**
* Configures the EC2 connection.
@ -91,7 +92,6 @@ public class AWSEC2RestClientModule extends EC2RestClientModule<AWSEC2Client, AW
.put(AvailabilityZoneAndRegionClient.class, AvailabilityZoneAndRegionAsyncClient.class)//
.put(ElasticBlockStoreClient.class, ElasticBlockStoreAsyncClient.class)//
.put(SpotInstanceClient.class, SpotInstanceAsyncClient.class)//
.put(TagClient.class, TagAsyncClient.class)//
.put(WindowsApi.class, WindowsAsyncApi.class)//
.put(TagApi.class, TagAsyncApi.class)//
.build();
@ -148,22 +148,11 @@ public class AWSEC2RestClientModule extends EC2RestClientModule<AWSEC2Client, AW
return in.getAMIServices();
}
@Singleton
@Provides
TagClient getTagServices(AWSEC2Client in) {
return in.getTagServices();
}
@Singleton
@Provides
TagAsyncClient getTagServices(AWSEC2AsyncClient in) {
return in.getTagServices();
}
@Override
protected void configure() {
bind(RunningInstance.Builder.class).to(AWSRunningInstance.Builder.class);
bind(RunInstancesOptions.class).to(AWSRunInstancesOptions.class);
bind(new TypeLiteral<Function<SpotInstanceRequest, AWSRunningInstance>>() {
}).to(SpotInstanceRequestToAWSRunningInstance.class);
super.configure();
}
}

View File

@ -32,7 +32,6 @@ import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
@ -46,11 +45,17 @@ import com.google.common.collect.Sets;
* @author Adrian Cole
*/
public class AWSRunningInstance extends RunningInstance {
public static Builder builder() {
return new Builder();
}
public static class Builder extends org.jclouds.ec2.domain.RunningInstance.Builder {
@Override
public Builder toBuilder() {
return new Builder().fromRunningInstance(this);
}
public static class Builder extends org.jclouds.ec2.domain.RunningInstance.Builder<Builder> {
private MonitoringState monitoringState;
private String placementGroup;
private Set<String> productCodes = Sets.newLinkedHashSet();
@ -59,19 +64,7 @@ public class AWSRunningInstance extends RunningInstance {
private String vpcId;
private Hypervisor hypervisor;
private Map<String, String> securityGroupIdToNames = Maps.newLinkedHashMap();
private Map<String, String> tags = Maps.newLinkedHashMap();
public Builder tags(Map<String, String> tags) {
this.tags = ImmutableMap.copyOf(checkNotNull(tags, "tags"));
return this;
}
public Builder tag(String key, String value) {
if (key != null)
this.tags.put(key, Strings.nullToEmpty(value));
return this;
}
public Builder securityGroupIdToNames(Map<String, String> securityGroupIdToNames) {
this.securityGroupIdToNames = ImmutableMap.copyOf(checkNotNull(securityGroupIdToNames,
"securityGroupIdToNames"));
@ -125,131 +118,6 @@ public class AWSRunningInstance extends RunningInstance {
return this;
}
@Override
public Builder amiLaunchIndex(String amiLaunchIndex) {
return Builder.class.cast(super.amiLaunchIndex(amiLaunchIndex));
}
@Override
public Builder availabilityZone(String availabilityZone) {
return Builder.class.cast(super.availabilityZone(availabilityZone));
}
@Override
public Builder devices(Map<String, BlockDevice> ebsBlockDevices) {
return Builder.class.cast(super.devices(ebsBlockDevices));
}
@Override
public Builder dnsName(String dnsName) {
return Builder.class.cast(super.dnsName(dnsName));
}
@Override
public Builder imageId(String imageId) {
return Builder.class.cast(super.imageId(imageId));
}
@Override
public Builder instanceId(String instanceId) {
return Builder.class.cast(super.instanceId(instanceId));
}
@Override
public Builder instanceState(InstanceState instanceState) {
return Builder.class.cast(super.instanceState(instanceState));
}
@Override
public Builder rawState(String rawState) {
return Builder.class.cast(super.rawState(rawState));
}
@Override
public Builder instanceType(String instanceType) {
return Builder.class.cast(super.instanceType(instanceType));
}
@Override
public Builder ipAddress(String ipAddress) {
return Builder.class.cast(super.ipAddress(ipAddress));
}
@Override
public Builder kernelId(String kernelId) {
return Builder.class.cast(super.kernelId(kernelId));
}
@Override
public Builder keyName(String keyName) {
return Builder.class.cast(super.keyName(keyName));
}
@Override
public Builder launchTime(Date launchTime) {
return Builder.class.cast(super.launchTime(launchTime));
}
@Override
public Builder platform(String platform) {
return Builder.class.cast(super.platform(platform));
}
@Override
public Builder privateDnsName(String privateDnsName) {
return Builder.class.cast(super.privateDnsName(privateDnsName));
}
@Override
public Builder privateIpAddress(String privateIpAddress) {
return Builder.class.cast(super.privateIpAddress(privateIpAddress));
}
@Override
public Builder ramdiskId(String ramdiskId) {
return Builder.class.cast(super.ramdiskId(ramdiskId));
}
@Override
public Builder reason(String reason) {
return Builder.class.cast(super.reason(reason));
}
@Override
public Builder region(String region) {
return Builder.class.cast(super.region(region));
}
@Override
public Builder rootDeviceName(String rootDeviceName) {
return Builder.class.cast(super.rootDeviceName(rootDeviceName));
}
@Override
public Builder rootDeviceType(RootDeviceType rootDeviceType) {
return Builder.class.cast(super.rootDeviceType(rootDeviceType));
}
@Override
public Builder virtualizationType(String virtualizationType) {
return Builder.class.cast(super.virtualizationType(virtualizationType));
}
@Override
public Builder device(String key, BlockDevice value) {
return Builder.class.cast(super.device(key, value));
}
@Override
public Builder groupName(String groupName) {
return Builder.class.cast(super.groupName(groupName));
}
@Override
public Builder groupNames(Iterable<String> groupNames) {
return Builder.class.cast(super.groupNames(groupNames));
}
@Override
public AWSRunningInstance build() {
return new AWSRunningInstance(region, securityGroupIdToNames, amiLaunchIndex, dnsName, imageId, instanceId,
@ -258,6 +126,24 @@ public class AWSRunningInstance extends RunningInstance {
rootDeviceName, ebsBlockDevices, monitoringState, placementGroup, productCodes, subnetId,
spotInstanceRequestId, vpcId, hypervisor, tags);
}
@Override
public Builder fromRunningInstance(RunningInstance in) {
super.fromRunningInstance(in);
if (in instanceof AWSRunningInstance) {
AWSRunningInstance awsIn = AWSRunningInstance.class.cast(in);
monitoringState(awsIn.monitoringState).placementGroup(awsIn.placementGroup)
.productCodes(awsIn.productCodes).subnetId(awsIn.subnetId)
.spotInstanceRequestId(awsIn.spotInstanceRequestId).vpcId(awsIn.vpcId).hypervisor(awsIn.hypervisor)
.securityGroupIdToNames(awsIn.securityGroupIdToNames);
}
return this;
}
@Override
protected Builder self() {
return this;
}
}
@ -273,7 +159,6 @@ public class AWSRunningInstance extends RunningInstance {
private final String vpcId;
private final Hypervisor hypervisor;
private final Map<String, String> securityGroupIdToNames;
private final Map<String, String> tags;
protected AWSRunningInstance(String region, Map<String, String> securityGroupIdToNames, String amiLaunchIndex,
String dnsName, String imageId, String instanceId, InstanceState instanceState, String rawState,
@ -286,7 +171,7 @@ public class AWSRunningInstance extends RunningInstance {
super(region, securityGroupIdToNames.values(), amiLaunchIndex, dnsName, imageId, instanceId, instanceState,
rawState, instanceType, ipAddress, kernelId, keyName, launchTime, availabilityZone, virtualizationType,
platform, privateDnsName, privateIpAddress, ramdiskId, reason, rootDeviceType, rootDeviceName,
ebsBlockDevices);
ebsBlockDevices, tags);
this.monitoringState = checkNotNull(monitoringState, "monitoringState");
this.placementGroup = placementGroup;
this.productCodes = ImmutableSet.copyOf(checkNotNull(productCodes, "productCodes"));
@ -296,7 +181,6 @@ public class AWSRunningInstance extends RunningInstance {
this.hypervisor = checkNotNull(hypervisor, "hypervisor");
this.securityGroupIdToNames = ImmutableMap.<String, String> copyOf(checkNotNull(securityGroupIdToNames,
"securityGroupIdToNames"));
this.tags = ImmutableMap.<String, String> copyOf(checkNotNull(tags, "tags"));
}
public Map<String, String> getSecurityGroupIdToNames() {
@ -356,18 +240,11 @@ public class AWSRunningInstance extends RunningInstance {
return subnetId;
}
/**
* tags that are present in the instance
*/
public Map<String, String> getTags() {
return tags;
}
@Override
protected ToStringHelper string() {
return super.string().add("monitoringState", monitoringState).add("placementGroup", placementGroup)
.add("subnetId", subnetId).add("spotInstanceRequestId", spotInstanceRequestId).add("vpcId", vpcId)
.add("hypervisor", hypervisor).add("tags", tags);
.add("hypervisor", hypervisor);
}
}

View File

@ -18,8 +18,6 @@
*/
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;
@ -32,7 +30,6 @@ import com.google.common.base.Function;
/**
* @author Adrian Cole
*/
@Singleton
public class SpotInstanceRequestToAWSRunningInstance implements Function<SpotInstanceRequest, AWSRunningInstance> {
@Override

View File

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

View File

@ -1,97 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.aws.ec2.services;
import static org.jclouds.aws.reference.FormParameters.ACTION;
import java.util.Map;
import java.util.Set;
import javax.inject.Named;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import org.jclouds.Fallbacks.EmptySetOnNotFoundOr404;
import org.jclouds.Fallbacks.VoidOnNotFoundOr404;
import org.jclouds.aws.ec2.binders.BindTagFiltersToIndexedFormParams;
import org.jclouds.aws.ec2.binders.BindTagsToIndexedFormParams;
import org.jclouds.aws.ec2.domain.Tag;
import org.jclouds.aws.ec2.util.TagFilters.FilterName;
import org.jclouds.aws.ec2.xml.DescribeTagsResponseHandler;
import org.jclouds.aws.filters.FormSigner;
import org.jclouds.ec2.binders.BindResourceIdsToIndexedFormParams;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull;
import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.EndpointParam;
import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.annotations.FormParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.VirtualHost;
import org.jclouds.rest.annotations.XMLResponseParser;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides access to EC2 Tags via their REST API.
*
* <h3>Important</h3>
* This will be removed in jclouds version 1.6
*
* @author grkvlt@apache.org
*/
@Deprecated
@RequestFilters(FormSigner.class)
@VirtualHost
public interface TagAsyncClient {
/**
* @see TagClient#createTagsInRegion(String, Iterable, Map)
*/
@Named("ec2:CreateTags")
@POST
@Path("/")
@FormParams(keys = ACTION, values = "CreateTags")
ListenableFuture<Void> createTagsInRegion(@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
@BinderParam(BindResourceIdsToIndexedFormParams.class) Iterable<String> resourceIds,
@BinderParam(BindTagsToIndexedFormParams.class) Map<String, String> tags);
/**
* @see TagClient#deleteTagsInRegion(String, Iterable, Map)
*/
@Named("ec2:DeleteTags")
@POST
@Path("/")
@FormParams(keys = ACTION, values = "DeleteTags")
@Fallback(VoidOnNotFoundOr404.class)
ListenableFuture<Void> deleteTagsInRegion(@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
@BinderParam(BindResourceIdsToIndexedFormParams.class) Iterable<String> resourceIds,
@BinderParam(BindTagsToIndexedFormParams.class) Map<String, String> tags);
/**
* @see TagClient#describeTagsInRegion(String, Map)
*/
@Named("ec2:DescribeTags")
@POST
@Path("/")
@FormParams(keys = ACTION, values = "DescribeTags")
@XMLResponseParser(DescribeTagsResponseHandler.class)
@Fallback(EmptySetOnNotFoundOr404.class)
ListenableFuture<? extends Set<Tag>> describeTagsInRegion(@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
@BinderParam(BindTagFiltersToIndexedFormParams.class) Map<FilterName, Iterable<?>> filters);
}

View File

@ -1,86 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.aws.ec2.services;
import java.util.Map;
import java.util.Set;
import org.jclouds.aws.ec2.domain.Tag;
import org.jclouds.aws.ec2.util.TagFilters.FilterName;
import org.jclouds.javax.annotation.Nullable;
/**
*
* Provides Tag services for EC2. For more information, refer to the Amazon EC2
* Developer Guide.
*
* <h3>Important</h3>
* This will be removed in jclouds version 1.6
*
* @author grkvlt@apache.org
* @see TagApi
*/
@Deprecated
public interface TagClient {
/**
* Creates tags.
*
* @param region
* Region to create the tag in.
* @param resourceIds
* IDs of the resources to tag.
* @param tags
* The tags to create.
* @see #describeTagsInRegion(String, Map)
* @see #deleteTagsInRegion(String, Iterable, Map)
*
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-CreateTags.html" />
*/
void createTagsInRegion(@Nullable String region, Iterable<String> resourceIds, Map<String, String> tags);
/**
* Deletes tags.
*
* @param region
* Region to delete the tags from
* @param resourceIds
* IDs of the tagged resources.
* @param tags
* The tags to delete.
*
* @see #describeTagsInRegion(String, Map)
* @see #createTagsInRegion(String, Iterable, Map)
*
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DeleteTags.html" />
*/
void deleteTagsInRegion(@Nullable String region, Iterable<String> resourceIds, Map<String, String> tags);
/**
* Returns filtered information about tags.
*
* @param region
* The bundleTask ID is tied to the Region.
* @param filters
* A collection of filters to apply before selecting the tags.
*
* @see #deleteTagsInRegion(String, Iterable, Map)
* @see #createTagsInRegion(String, Iterable, Map)
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeTags.html" />
*/
Set<Tag> describeTagsInRegion(@Nullable String region, Map<FilterName, Iterable<?>> filters);
}

View File

@ -18,24 +18,23 @@
*/
package org.jclouds.aws.ec2.xml;
import static org.jclouds.util.SaxUtils.currentOrNull;
import static org.jclouds.util.SaxUtils.equalsOrSuffix;
import java.util.Set;
import javax.inject.Inject;
import org.jclouds.aws.ec2.domain.AWSRunningInstance;
import org.jclouds.date.DateCodecFactory;
import org.jclouds.ec2.domain.Reservation;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.ec2.xml.TagSetHandler;
import org.jclouds.location.Region;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import com.google.common.base.Supplier;
import com.google.common.collect.Sets;
import com.google.inject.Provider;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
/**
* Parses the following XML document:
@ -47,42 +46,51 @@ import com.google.inject.Provider;
*/
public class AWSDescribeInstancesResponseHandler extends
BaseAWSReservationHandler<Set<Reservation<? extends RunningInstance>>> {
private Set<Reservation<? extends RunningInstance>> reservations = Sets.newLinkedHashSet();
private final TagSetHandler tagSetHandler;
private Builder<Reservation<? extends RunningInstance>> reservations = ImmutableSet.<Reservation<? extends RunningInstance>>builder();
private boolean inTagSet;
private String key;
private String value;
@Inject
AWSDescribeInstancesResponseHandler(DateCodecFactory dateCodecFactory, @Region Supplier<String> defaultRegion,
Provider<AWSRunningInstance.Builder> builderProvider, TagSetHandler tagSetHandler) {
super(dateCodecFactory, defaultRegion, builderProvider);
TagSetHandler tagSetHandler) {
super(dateCodecFactory, defaultRegion);
this.tagSetHandler = tagSetHandler;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
super.startElement(uri, localName, qName, attrs);
public void startElement(String uri, String name, String qName, Attributes attrs) throws SAXException {
super.startElement(uri, name, qName, attrs);
if (equalsOrSuffix(qName, "tagSet")) {
inTagSet = true;
}
if (inTagSet) {
tagSetHandler.startElement(uri, name, qName, attrs);
}
}
@Override
public void characters(char ch[], int start, int length) {
if (inTagSet) {
tagSetHandler.characters(ch, start, length);
} else {
super.characters(ch, start, length);
}
}
@Override
public void endElement(String uri, String name, String qName) {
if (equalsOrSuffix(qName, "tagSet")) {
inTagSet = false;
builder.tags(tagSetHandler.getResult());
} else if (inTagSet) {
if (equalsOrSuffix(qName, "key")) {
key = currentOrNull(currentText);
} else if (equalsOrSuffix(qName, "value")) {
value = currentOrNull(currentText);
}
tagSetHandler.endElement(uri, name, qName);
}
super.endElement(uri, name, qName);
}
@Override
public Set<Reservation<? extends RunningInstance>> getResult() {
return reservations;
return reservations.build();
}
protected boolean endOfReservationItem() {
@ -93,10 +101,6 @@ public class AWSDescribeInstancesResponseHandler extends
protected void inItem() {
if (endOfReservationItem()) {
reservations.add(super.newReservation());
} else if (inTagSet) {
builder.tag(key, value);
key = null;
value = null;
} else {
super.inItem();
}

View File

@ -20,14 +20,12 @@ package org.jclouds.aws.ec2.xml;
import javax.inject.Inject;
import org.jclouds.aws.ec2.domain.AWSRunningInstance;
import org.jclouds.date.DateCodecFactory;
import org.jclouds.ec2.domain.Reservation;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.location.Region;
import com.google.common.base.Supplier;
import com.google.inject.Provider;
/**
* Parses the following XML document:
@ -40,9 +38,8 @@ import com.google.inject.Provider;
public class AWSRunInstancesResponseHandler extends BaseAWSReservationHandler<Reservation<? extends RunningInstance>> {
@Inject
AWSRunInstancesResponseHandler(DateCodecFactory dateCodecFactory, @Region Supplier<String> defaultRegion,
Provider<AWSRunningInstance.Builder> builderProvider) {
super(dateCodecFactory, defaultRegion, builderProvider);
AWSRunInstancesResponseHandler(DateCodecFactory dateCodecFactory, @Region Supplier<String> defaultRegion) {
super(dateCodecFactory, defaultRegion);
}
@Override

View File

@ -49,7 +49,6 @@ import org.xml.sax.SAXException;
import com.google.common.base.Supplier;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.inject.Provider;
/**
*
@ -62,21 +61,21 @@ public abstract class BaseAWSReservationHandler<T> extends HandlerForGeneratedRe
protected final DateCodec dateCodec;
protected final Supplier<String> defaultRegion;
protected final Provider<AWSRunningInstance.Builder> builderProvider;
@Inject
public BaseAWSReservationHandler(DateCodecFactory dateCodecFactory, @Region Supplier<String> defaultRegion,
Provider<AWSRunningInstance.Builder> builderProvider) {
public BaseAWSReservationHandler(DateCodecFactory dateCodecFactory, @Region Supplier<String> defaultRegion) {
this.dateCodec = dateCodecFactory.iso8601();
this.defaultRegion = defaultRegion;
this.builderProvider = builderProvider;
this.builder = builderProvider.get();
}
protected AWSRunningInstance.Builder builder = newBuilder();
protected AWSRunningInstance.Builder newBuilder() {
return AWSRunningInstance.builder();
}
protected StringBuilder currentText = new StringBuilder();
protected AWSRunningInstance.Builder builder;
protected int itemDepth;
boolean inInstancesSet;
// attachments
@ -215,7 +214,7 @@ public abstract class BaseAWSReservationHandler<T> extends HandlerForGeneratedRe
if (endOfInstanceItem()) {
refineBuilderBeforeAddingInstance();
instances.add(builder.build());
builder = builderProvider.get();
builder = newBuilder();
}
}

View File

@ -1,73 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.aws.ec2.xml;
import java.util.Set;
import javax.inject.Inject;
import org.jclouds.aws.ec2.domain.Tag;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.ParseSax.HandlerWithResult;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import com.google.common.collect.Sets;
/**
* @author grkvlt@apache.org
*/
public class DescribeTagsResponseHandler extends ParseSax.HandlerWithResult<Set<Tag>> {
private Set<Tag> tags = Sets.newLinkedHashSet();
private final TagHandler tagHandler;
@Inject
public DescribeTagsResponseHandler(TagHandler tagHandler) {
this.tagHandler = tagHandler;
}
public Set<Tag> getResult() {
return tags;
}
@Override
public HandlerWithResult<Set<Tag>> setContext(HttpRequest request) {
tagHandler.setContext(request);
return super.setContext(request);
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (!qName.equals("item"))
tagHandler.startElement(uri, localName, qName, attributes);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equals("item")) {
tags.add(tagHandler.getResult());
}
tagHandler.endElement(uri, localName, qName);
}
public void characters(char ch[], int start, int length) {
tagHandler.characters(ch, start, length);
}
}

View File

@ -28,6 +28,7 @@ import org.jclouds.aws.ec2.domain.SpotInstanceRequest.Builder;
import org.jclouds.aws.util.AWSUtils;
import org.jclouds.date.DateCodec;
import org.jclouds.date.DateCodecFactory;
import org.jclouds.ec2.xml.TagSetHandler;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.location.Region;
import org.xml.sax.Attributes;
@ -92,7 +93,7 @@ public class SpotInstanceHandler extends ParseSax.HandlerForGeneratedRequestWith
inTagSet = false;
builder.tags(tagSetHandler.getResult());
} else if (inTagSet) {
tagSetHandler.endElement(uri, name, qName);
tagSetHandler.endElement(uri, name, qName);
}
if (qName.equals("launchSpecification")) {
@ -143,9 +144,9 @@ public class SpotInstanceHandler extends ParseSax.HandlerForGeneratedRequestWith
@Override
public void characters(char ch[], int start, int length) {
if (inLaunchSpecification) {
launchSpecificationHandler.characters(ch, start, length);
launchSpecificationHandler.characters(ch, start, length);
} else if (inTagSet) {
tagSetHandler.characters(ch, start, length);
tagSetHandler.characters(ch, start, length);
} else {
currentText.append(ch, start, length);
}

View File

@ -1,58 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.aws.ec2.xml;
import org.jclouds.aws.ec2.domain.Tag;
import org.jclouds.aws.ec2.util.TagFilters.ResourceType;
import org.jclouds.http.functions.ParseSax;
import org.xml.sax.SAXException;
/**
* @author grkvlt@apache.org
*/
public class TagHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Tag> {
private StringBuilder currentText = new StringBuilder();
private String resourceId;
private ResourceType resourceType;
private String key;
private String value;
public Tag getResult() {
Tag returnVal = new Tag(resourceId, resourceType, key, value);
return returnVal;
}
public void endElement(String uri, String name, String qName) throws SAXException {
if (qName.equals("resourceId")) {
this.resourceId = currentText.toString().trim();
} else if (qName.equals("resourceType")) {
resourceType = ResourceType.fromValue(currentText.toString().trim());
} else if (qName.equals("key")) {
key = currentText.toString().trim();
} else if (qName.equals("value")) {
value = currentText.toString().trim();
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
}

View File

@ -1,85 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.aws.ec2.xml;
import static org.jclouds.util.SaxUtils.currentOrNull;
import static org.jclouds.util.SaxUtils.equalsOrSuffix;
import java.util.Map;
import org.jclouds.http.functions.ParseSax;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
/**
* @author grkvlt@apache.org
*/
public class TagSetHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Map<String, String>> {
private StringBuilder currentText = new StringBuilder();
private ImmutableMap.Builder<String, String> result;
private boolean inItem = false;
private String key;
private String value;
public TagSetHandler() {
super();
}
public Map<String, String> getResult() {
return result.build();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (equalsOrSuffix(qName, "tagSet")) {
result = ImmutableMap.builder();
} else if (qName.equals("item")) {
inItem = true;
key = null;
value = null;
}
currentText = new StringBuilder();
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equals("item")) {
inItem = false;
if (key != null) {
result.put(key, Strings.nullToEmpty(value));
}
}
if (inItem) {
if (qName.equals("key")) {
key = currentOrNull(currentText);
} else if (qName.equals("value")) {
value = currentOrNull(currentText);
}
}
}
@Override
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
}

View File

@ -49,7 +49,6 @@ public class AWSEC2AsyncClientTest extends BaseAWSEC2AsyncClientTest<AWSEC2Async
assert syncClient.getSecurityGroupServices() != null;
assert syncClient.getPlacementGroupServices() != null;
assert syncClient.getWindowsServices() != null;
assert syncClient.getTagServices() != null;
}
@ -64,7 +63,6 @@ public class AWSEC2AsyncClientTest extends BaseAWSEC2AsyncClientTest<AWSEC2Async
assert asyncClient.getSecurityGroupServices() != null;
assert asyncClient.getPlacementGroupServices() != null;
assert asyncClient.getWindowsServices() != null;
assert asyncClient.getTagServices() != null;
}
@BeforeClass

View File

@ -77,13 +77,6 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
group = "ec2";
}
// aws-ec2 supports userMetadata
@Override
protected void checkUserMetadataContains(NodeMetadata node, ImmutableMap<String, String> userMetadata) {
assert node.getUserMetadata().equals(userMetadata) : String.format("node userMetadata did not match %s %s",
userMetadata, node);
}
@Override
@Test
public void testExtendedOptionsAndLogin() throws Exception {
@ -103,12 +96,14 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
Date before = new Date();
ImmutableMap<String, String> userMetadata = ImmutableMap.<String, String> of("test", group);
ImmutableSet<String> tags = ImmutableSet. of(group);
ImmutableSet<String> tags = ImmutableSet.of(group);
// note that if you change the location, you must also specify image parameters
Template template = client.templateBuilder().locationId(region).osFamily(AMZN_LINUX).os64Bit(true).build();
template.getOptions().tags(tags);
template.getOptions().userMetadata(userMetadata);
template.getOptions().tags(tags);
template.getOptions().as(AWSEC2TemplateOptions.class).enableMonitoring();
template.getOptions().as(AWSEC2TemplateOptions.class).spotPrice(0.3f);
@ -137,9 +132,6 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
Set<? extends NodeMetadata> nodes = client.createNodesInGroup(group, 1, template);
NodeMetadata first = getOnlyElement(nodes);
// Name metadata should turn into node.name
assertEquals(first.getName(), group);
checkUserMetadataContains(first, userMetadata);
checkTagsInNodeEquals(first, tags);

View File

@ -1,168 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.aws.ec2.compute;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import java.util.Set;
import org.jclouds.aws.ec2.AWSEC2ApiMetadata;
import org.jclouds.aws.ec2.AWSEC2Client;
import org.jclouds.aws.ec2.domain.AWSRunningInstance;
import org.jclouds.aws.ec2.services.AWSSecurityGroupClient;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest;
import org.jclouds.compute.predicates.NodePredicates;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.compute.EC2ComputeServiceLiveTest;
import org.jclouds.ec2.domain.KeyPair;
import org.jclouds.ec2.domain.SecurityGroup;
import org.jclouds.ec2.services.InstanceClient;
import org.jclouds.ec2.services.KeyPairClient;
import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.base.Stopwatch;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
/**
*
* Disabled, as it doesn't pass
*
* @author Aled Sage
*/
@Test(enabled = false, groups = "live", singleThreaded = true, testName = "IncidentalResourcesGetCleanedUpLiveTest")
public class IncidentalResourcesGetCleanedUpLiveTest extends BaseComputeServiceContextLiveTest {
public IncidentalResourcesGetCleanedUpLiveTest() {
provider = "aws-ec2";
}
@Test(enabled = false)
public void testIncidentalResourcesGetCleanedUpOnlyOnLastInstanceDestroyNode() throws Exception {
Function<String,Void> destroyer = new Function<String,Void>() {
@Override
public Void apply(String instanceId) {
view.getComputeService().destroyNode(instanceId);
return null;
}
};
runIncidentalResourcesGetCleanedUpOnlyOnLastInstanceDestroy(destroyer);
}
@Test(enabled = false)
public void testIncidentalResourcesGetCleanedUpOnlyOnLastInstanceDestroyNodesMatching() throws Exception {
Function<String,Void> destroyer = new Function<String,Void>() {
@Override
public Void apply(String instanceId) {
view.getComputeService().destroyNodesMatching(NodePredicates.<NodeMetadata>withIds(instanceId));
return null;
}
};
runIncidentalResourcesGetCleanedUpOnlyOnLastInstanceDestroy(destroyer);
}
private void runIncidentalResourcesGetCleanedUpOnlyOnLastInstanceDestroy(Function<String,Void> destroyer) throws Exception {
AWSSecurityGroupClient securityGroupClient = AWSEC2Client.class.cast(view.unwrap(AWSEC2ApiMetadata.CONTEXT_TOKEN).getApi())
.getSecurityGroupServices();
KeyPairClient keyPairClient = EC2Client.class.cast(view.unwrap(AWSEC2ApiMetadata.CONTEXT_TOKEN).getApi())
.getKeyPairServices();
InstanceClient instanceClient = EC2Client.class.cast(view.unwrap(AWSEC2ApiMetadata.CONTEXT_TOKEN).getApi())
.getInstanceServices();
String group = "aws-ec2-incidental";
String region = null;
try {
// Create two instances
// TODO set spotPrice(0.3f) ?
Template template = view.getComputeService().templateBuilder().build();
Set<? extends NodeMetadata> nodes = view.getComputeService().createNodesInGroup(group, 2, template);
NodeMetadata first = Iterables.get(nodes, 0);
NodeMetadata second = Iterables.get(nodes, 1);
String instanceId1 = Iterables.get(nodes, 0).getProviderId();
String instanceId2 = Iterables.get(nodes, 1).getProviderId();
AWSRunningInstance instance1 = AWSRunningInstance.class.cast(EC2ComputeServiceLiveTest.getInstance(instanceClient, instanceId1));
AWSRunningInstance instance2 = AWSRunningInstance.class.cast(EC2ComputeServiceLiveTest.getInstance(instanceClient, instanceId2));
// Assert the two instances are in the same groups
region = instance1.getRegion();
String expectedSecurityGroupName = "jclouds#" + group;
assertEquals(instance1.getRegion(), region);
assertNotNull(instance1.getKeyName());
assertEquals(instance1.getRegion(), instance2.getRegion(), "Nodes are not in the same region");
assertEquals(instance1.getKeyName(), instance2.getKeyName(), "Nodes do not have same key-pair name");
assertEquals(instance1.getGroupNames(), instance2.getGroupNames(), "Nodes are not in the same group");
assertEquals(instance1.getGroupNames(), ImmutableSet.of(expectedSecurityGroupName), "Nodes are not in the expected security group");
// Assert a single key-pair and security group has been created
String expectedKeyPairName = instance1.getKeyName();
Set<SecurityGroup> securityGroups = securityGroupClient.describeSecurityGroupsInRegion(region, expectedSecurityGroupName);
Set<KeyPair> keyPairs = keyPairClient.describeKeyPairsInRegion(region, expectedKeyPairName);
assertEquals(securityGroups.size(), 1);
assertEquals(Iterables.get(securityGroups, 0).getName(), expectedSecurityGroupName);
assertEquals(keyPairs.size(), 1);
assertEquals(Iterables.get(keyPairs, 0).getKeyName(), expectedKeyPairName);
// Destroy the first node; the key-pair and security-group should still remain
destroyer.apply(first.getId());
Set<SecurityGroup> securityGroupsAfterDestroyFirst = securityGroupClient.describeSecurityGroupsInRegion(region, expectedSecurityGroupName);
Set<KeyPair> keyPairsAfterDestroyFirst = keyPairClient.describeKeyPairsInRegion(region, expectedKeyPairName);
assertEquals(securityGroupsAfterDestroyFirst, securityGroups);
assertEquals(keyPairsAfterDestroyFirst, keyPairs);
// Destroy the second node; the key-pair and security-group should be automatically deleted
// It can take some time after destroyNode returns for the securityGroup and keyPair to be completely removed.
// Therefore try repeatedly.
destroyer.apply(second.getId());
final int TIMEOUT_MS = 30*1000;
boolean firstAttempt = true;
boolean done;
Set<SecurityGroup> securityGroupsAfterDestroyAll;
Set<KeyPair> keyPairsAfterDestroyAll;
Stopwatch stopwatch = new Stopwatch();
stopwatch.start();
do {
if (!firstAttempt) Thread.sleep(1000);
firstAttempt = false;
securityGroupsAfterDestroyAll = securityGroupClient.describeSecurityGroupsInRegion(region, expectedSecurityGroupName);
keyPairsAfterDestroyAll = keyPairClient.describeKeyPairsInRegion(region, expectedKeyPairName);
done = securityGroupsAfterDestroyAll.isEmpty() && keyPairsAfterDestroyAll.isEmpty();
} while (!done && stopwatch.elapsedMillis() < TIMEOUT_MS);
assertEquals(securityGroupsAfterDestroyAll, ImmutableSet.of());
assertEquals(keyPairsAfterDestroyAll, ImmutableSet.of());
} finally {
view.getComputeService().destroyNodesMatching(NodePredicates.inGroup(group));
if (region != null) EC2ComputeServiceLiveTest.cleanupExtendedStuffInRegion(region, securityGroupClient, keyPairClient, group);
}
}
}

View File

@ -0,0 +1,101 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.aws.ec2.compute.functions;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.testng.Assert.assertEquals;
import java.util.Set;
import org.jclouds.aws.ec2.AWSEC2Client;
import org.jclouds.aws.ec2.domain.AWSRunningInstance;
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
import org.jclouds.aws.ec2.services.AWSInstanceClient;
import org.jclouds.aws.ec2.services.SpotInstanceClient;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.domain.Reservation;
import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
/**
* @author Adrian Cole
*/
@Test(groups = "unit")
public class PresentSpotRequestsAndInstancesTest {
AWSRunningInstance instance1 = createMock(AWSRunningInstance.class);
AWSRunningInstance instance2 = createMock(AWSRunningInstance.class);
@SuppressWarnings("unchecked")
@Test
public void testWhenInstancesPresentSingleCall() {
AWSEC2Client client = createMock(AWSEC2Client.class);
AWSInstanceClient instanceClient = createMock(AWSInstanceClient.class);
Function<SpotInstanceRequest, AWSRunningInstance> converter = createMock(Function.class);
expect(client.getInstanceServices()).andReturn(instanceClient);
// avoid imatcher fail. if you change this, be sure to check multiple jres
expect(instanceClient.describeInstancesInRegion("us-east-1", "i-aaaa", "i-bbbb")).andReturn(
Set.class.cast(ImmutableSet.of(Reservation.<AWSRunningInstance> builder().region("us-east-1")
.instances(ImmutableSet.of(instance1, instance2)).build())));
replay(client, instanceClient, converter);
PresentSpotRequestsAndInstances fn = new PresentSpotRequestsAndInstances(client, converter);
assertEquals(fn.apply(ImmutableSet.of(new RegionAndName("us-east-1", "i-aaaa"), new RegionAndName("us-east-1",
"i-bbbb"))), ImmutableSet.of(instance1, instance2));
verify(client, instanceClient, converter);
}
SpotInstanceRequest spot1 = createMock(SpotInstanceRequest.class);
SpotInstanceRequest spot2 = createMock(SpotInstanceRequest.class);
@Test
public void testWhenSpotsPresentSingleCall() {
Function<SpotInstanceRequest, AWSRunningInstance> converter = Functions.forMap(ImmutableMap.of(spot1, instance1,
spot2, instance2));
AWSEC2Client client = createMock(AWSEC2Client.class);
SpotInstanceClient spotClient = createMock(SpotInstanceClient.class);
expect(client.getSpotInstanceServices()).andReturn(spotClient);
expect(spotClient.describeSpotInstanceRequestsInRegion("us-east-1", "sir-aaaa", "sir-bbbb")).andReturn(
ImmutableSet.of(spot1, spot2));
replay(client, spotClient);
PresentSpotRequestsAndInstances fn = new PresentSpotRequestsAndInstances(client, converter);
assertEquals(fn.apply(ImmutableSet.of(new RegionAndName("us-east-1", "sir-aaaa"), new RegionAndName("us-east-1",
"sir-bbbb"))), ImmutableSet.of(instance1, instance2));
verify(client, spotClient);
}
}

View File

@ -1,108 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.aws.ec2.services;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Map;
import org.jclouds.Fallbacks.EmptySetOnNotFoundOr404;
import org.jclouds.Fallbacks.VoidOnNotFoundOr404;
import org.jclouds.aws.ec2.util.TagFilters;
import org.jclouds.aws.ec2.xml.DescribeTagsResponseHandler;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.ReleasePayloadAndReturn;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
/**
* Tests behavior of {@code TagsAsyncClient}
*
* @author grkvlt@apache.org
*/
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "TagsAsyncClientTest")
public class TagAsyncClientTest extends BaseAWSEC2AsyncClientTest<TagAsyncClient> {
public void testDeleteTags() throws SecurityException, NoSuchMethodException, IOException {
Method method = TagAsyncClient.class.getMethod("deleteTagsInRegion", String.class, Iterable.class, Map.class);
HttpRequest request = processor.createRequest(method, null, ImmutableList.<String>builder().add("xxx").build(), ImmutableMap.<String, String>builder().put("yyy", "zzz").build());
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
assertPayloadEquals(request, "Action=DeleteTags&Tag.1.Key=yyy&Tag.1.Value=zzz&ResourceId.1=xxx",
"application/x-www-form-urlencoded", false);
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
assertFallbackClassEquals(method, VoidOnNotFoundOr404.class);
checkFilters(request);
}
public void testCreateTags() throws SecurityException, NoSuchMethodException, IOException {
Method method = TagAsyncClient.class.getMethod("createTagsInRegion", String.class, Iterable.class, Map.class);
HttpRequest request = processor.createRequest(method, null, ImmutableList.<String>builder().add("xxx").build(), ImmutableMap.<String, String>builder().put("yyy", "zzz").build());
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
assertPayloadEquals(request, "Action=CreateTags&Tag.1.Key=yyy&Tag.1.Value=zzz&ResourceId.1=xxx",
"application/x-www-form-urlencoded", false);
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
assertFallbackClassEquals(method, null);
checkFilters(request);
}
public void testDescribeTags() throws SecurityException, NoSuchMethodException, IOException {
Method method = TagAsyncClient.class.getMethod("describeTagsInRegion", String.class, Map.class);
HttpRequest request = processor.createRequest(method, null, TagFilters.filters().build());
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
assertPayloadEquals(request, "Action=DescribeTags",
"application/x-www-form-urlencoded", false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, DescribeTagsResponseHandler.class);
assertFallbackClassEquals(method, EmptySetOnNotFoundOr404.class);
checkFilters(request);
}
public void testDescribeTagsArgs() throws SecurityException, NoSuchMethodException, IOException {
Method method = TagAsyncClient.class.getMethod("describeTagsInRegion", String.class, Map.class);
HttpRequest request = processor.createRequest(method, null, TagFilters.filters().key("one").key("two").build());
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
assertPayloadEquals(request, "Action=DescribeTags&Filter.1.Name=key&Filter.1.Value.1=one&Filter.1.Value.2=two",
"application/x-www-form-urlencoded", false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, DescribeTagsResponseHandler.class);
assertFallbackClassEquals(method, EmptySetOnNotFoundOr404.class);
checkFilters(request);
}
}

View File

@ -1,118 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.aws.ec2.services;
import static com.google.common.collect.Iterables.getOnlyElement;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import java.util.Set;
import org.jclouds.aws.ec2.AWSEC2ApiMetadata;
import org.jclouds.aws.ec2.domain.AWSRunningInstance;
import org.jclouds.aws.ec2.domain.Tag;
import org.jclouds.aws.ec2.util.TagFilters;
import org.jclouds.aws.ec2.util.TagFilters.ResourceType;
import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
/**
* Tests live behavior of {@code TagClient}
*
* @author grkvlt@apache.org
*/
@Test(groups = "live", singleThreaded = true)
public class TagClientLiveTest extends BaseComputeServiceContextLiveTest {
public TagClientLiveTest() {
provider = "aws-ec2";
}
private TagClient client;
protected String testGroup;
@Override
@BeforeClass(groups = { "integration", "live" })
public void setupContext() {
super.setupContext();
client = view.unwrap(AWSEC2ApiMetadata.CONTEXT_TOKEN).getApi().getTagServices();
try {
testGroup = view.unwrap(AWSEC2ApiMetadata.CONTEXT_TOKEN).getApi().getSecurityGroupServices().createSecurityGroupInRegionAndReturnId(null,
"test-group", "test-group");
} catch (IllegalStateException e) {
// already exists
testGroup = Iterables.get(
view.unwrap(AWSEC2ApiMetadata.CONTEXT_TOKEN).getApi().getSecurityGroupServices().describeSecurityGroupsInRegion(null, "test-group"), 0)
.getId();
}
}
@Override
@AfterClass(groups = { "integration", "live" })
protected void tearDownContext() {
view.unwrap(AWSEC2ApiMetadata.CONTEXT_TOKEN).getApi().getSecurityGroupServices().deleteSecurityGroupInRegionById(null, testGroup);
super.tearDownContext();
}
public static final String PREFIX = System.getProperty("user.name") + "-ec2";
@Test
void test() {
cleanupTag(testGroup, "test-key");
cleanupTag(testGroup, "empty-key");
try {
client.createTagsInRegion(null, ImmutableList.<String>builder().add(testGroup).build(), ImmutableMap.<String, String>builder().put("test-key", "test-value").build());
checkTag(testGroup, ResourceType.SECURITY_GROUP, "test-key", "test-value");
client.createTagsInRegion(null, ImmutableList.<String>builder().add(testGroup).build(), ImmutableMap.<String, String>builder().put("empty-key", "").build());
checkTag(testGroup, ResourceType.SECURITY_GROUP, "empty-key", "");
} finally {
cleanupTag(testGroup, "test-key");
cleanupTag(testGroup, "empty-key");
}
}
protected void cleanupTag(String resourceId, String key) {
try {
client.deleteTagsInRegion(null, ImmutableList.<String>builder().add(resourceId).build(), ImmutableMap.<String, String>builder().put(key, null).build());
} catch (Exception e) {
// Ignore
}
}
protected void checkTag(String resourceId, ResourceType resourceType, String key, String value) {
Set<Tag> results = client.describeTagsInRegion(null, TagFilters.filters().resourceId(resourceId).resourceType(resourceType).keyValuePair(key, value).build());
assertNotNull(results);
assertEquals(results.size(), 1);
Tag tag = Iterables.getOnlyElement(results);
assertEquals(tag.getResourceId(), resourceId);
assertEquals(tag.getResourceType(), resourceType);
assertEquals(tag.getKey(), key);
assertEquals(tag.getValue(), value);
}
protected AWSRunningInstance getInstance(AWSInstanceClient instanceClient, String id) {
return getOnlyElement(getOnlyElement(instanceClient.describeInstancesInRegion(null, id)));
}
}