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.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_AMI_OWNERS;
import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_AUTO_ALLOCATE_ELASTIC_IPS; 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 static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_TIMEOUT_SECURITYGROUP_PRESENT;
import java.net.URI; 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_TIMEOUT_SECURITYGROUP_PRESENT, "500");
properties.setProperty(PROPERTY_EC2_AUTO_ALLOCATE_ELASTIC_IPS, "false"); properties.setProperty(PROPERTY_EC2_AUTO_ALLOCATE_ELASTIC_IPS, "false");
properties.setProperty(RESOURCENAME_DELIMITER, "#"); properties.setProperty(RESOURCENAME_DELIMITER, "#");
properties.setProperty(PROPERTY_EC2_GENERATE_INSTANCE_NAMES, "true");
return properties; 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_RUNNING;
import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; 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.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 static org.jclouds.util.Preconditions2.checkNotEmpty;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
@ -41,10 +45,13 @@ import org.jclouds.Constants;
import org.jclouds.aws.util.AWSUtils; import org.jclouds.aws.util.AWSUtils;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.callables.RunScriptOnNode; import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.extensions.ImageExtension; import org.jclouds.compute.extensions.ImageExtension;
import org.jclouds.compute.functions.GroupNamingConvention; 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.compute.options.EC2TemplateOptions;
import org.jclouds.ec2.domain.KeyPair; import org.jclouds.ec2.domain.KeyPair;
import org.jclouds.ec2.domain.RunningInstance; import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.ec2.domain.Tag;
import org.jclouds.ec2.util.TagFilterBuilder;
import org.jclouds.predicates.Retryables; import org.jclouds.predicates.Retryables;
import org.jclouds.scriptbuilder.functions.InitAdminAccess; 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.Predicate;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableMultimap.Builder; import com.google.common.collect.ImmutableMultimap.Builder;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.inject.Inject; import com.google.inject.Inject;
/** /**
@ -89,10 +102,11 @@ import com.google.inject.Inject;
*/ */
@Singleton @Singleton
public class EC2ComputeService extends BaseComputeService { public class EC2ComputeService extends BaseComputeService {
private final EC2Client ec2Client; private final EC2Client client;
private final ConcurrentMap<RegionAndName, KeyPair> credentialsMap; private final ConcurrentMap<RegionAndName, KeyPair> credentialsMap;
private final LoadingCache<RegionAndName, String> securityGroupMap; private final LoadingCache<RegionAndName, String> securityGroupMap;
private final Factory namingConvention; private final Factory namingConvention;
private final boolean generateInstanceNames;
@Inject @Inject
protected EC2ComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore, protected EC2ComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore,
@ -109,19 +123,74 @@ public class EC2ComputeService extends BaseComputeService {
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, 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, ConcurrentMap<RegionAndName, KeyPair> credentialsMap,
@Named("SECURITY") LoadingCache<RegionAndName, String> securityGroupMap, @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, super(context, credentialStore, images, sizes, locations, listNodesStrategy, getImageStrategy,
getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy,
startNodeStrategy, stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, startNodeStrategy, stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning,
nodeTerminated, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, nodeTerminated, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory,
persistNodeCredentials, timeouts, executor, imageExtension); persistNodeCredentials, timeouts, executor, imageExtension);
this.ec2Client = ec2Client; this.client = client;
this.credentialsMap = credentialsMap; this.credentialsMap = credentialsMap;
this.securityGroupMap = securityGroupMap; this.securityGroupMap = securityGroupMap;
this.namingConvention = namingConvention; 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) @Inject(optional = true)
@ -137,9 +206,9 @@ public class EC2ComputeService extends BaseComputeService {
checkNotEmpty(group, "group"); checkNotEmpty(group, "group");
String groupName = namingConvention.create().sharedNameForGroup(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); logger.debug(">> deleting securityGroup(%s)", groupName);
ec2Client.getSecurityGroupServices().deleteSecurityGroupInRegion(region, groupName); client.getSecurityGroupServices().deleteSecurityGroupInRegion(region, groupName);
// TODO: test this clear happens // TODO: test this clear happens
securityGroupMap.invalidate(new RegionNameAndIngressRules(region, groupName, null, false)); securityGroupMap.invalidate(new RegionNameAndIngressRules(region, groupName, null, false));
logger.debug("<< deleted securityGroup(%s)", groupName); logger.debug("<< deleted securityGroup(%s)", groupName);
@ -148,20 +217,20 @@ public class EC2ComputeService extends BaseComputeService {
@VisibleForTesting @VisibleForTesting
void deleteKeyPair(String region, String group) { void deleteKeyPair(String region, String group) {
for (KeyPair keyPair : ec2Client.getKeyPairServices().describeKeyPairsInRegion(region)) { for (KeyPair keyPair : client.getKeyPairServices().describeKeyPairsInRegion(region)) {
String keyName = keyPair.getKeyName(); String keyName = keyPair.getKeyName();
Predicate<String> keyNameMatcher = namingConvention.create().containsGroup(group); Predicate<String> keyNameMatcher = namingConvention.create().containsGroup(group);
String oldKeyNameRegex = String.format("jclouds#%s#%s#%s", group, region, "[0-9a-f]+").replace('#', delimiter); 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 // old keypair pattern too verbose as it has an unnecessary region qualifier
if (keyNameMatcher.apply(keyName) || keyName.matches(oldKeyNameRegex)) { 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))); .describeInstancesInRegion(region)), usingKeyPairAndNotDead(keyPair)));
if (instancesUsingKeyPair.size() > 0) { if (instancesUsingKeyPair.size() > 0) {
logger.debug("<< inUse keyPair(%s), by (%s)", keyPair.getKeyName(), instancesUsingKeyPair); logger.debug("<< inUse keyPair(%s), by (%s)", keyPair.getKeyName(), instancesUsingKeyPair);
} else { } else {
logger.debug(">> deleting keyPair(%s)", keyPair.getKeyName()); logger.debug(">> deleting keyPair(%s)", keyPair.getKeyName());
ec2Client.getKeyPairServices().deleteKeyPairInRegion(region, keyPair.getKeyName()); client.getKeyPairServices().deleteKeyPairInRegion(region, keyPair.getKeyName());
// TODO: test this clear happens // TODO: test this clear happens
credentialsMap.remove(new RegionAndName(region, keyPair.getKeyName())); credentialsMap.remove(new RegionAndName(region, keyPair.getKeyName()));
credentialsMap.remove(new RegionAndName(region, group)); credentialsMap.remove(new RegionAndName(region, group));
@ -184,7 +253,6 @@ public class EC2ComputeService extends BaseComputeService {
protected Predicate<RunningInstance> usingKeyPairAndNotDead(final KeyPair keyPair) { protected Predicate<RunningInstance> usingKeyPairAndNotDead(final KeyPair keyPair) {
return new Predicate<RunningInstance>() { return new Predicate<RunningInstance>() {
@Override @Override
public boolean apply(RunningInstance input) { public boolean apply(RunningInstance input) {
switch (input.getInstanceState()) { switch (input.getInstanceState()) {
@ -194,7 +262,6 @@ public class EC2ComputeService extends BaseComputeService {
} }
return keyPair.getKeyName().equals(input.getKeyName()); return keyPair.getKeyName().equals(input.getKeyName());
} }
}; };
} }

View File

@ -18,26 +18,33 @@
*/ */
package org.jclouds.ec2.compute.domain; 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 * @author Adrian Cole
*/ */
public class RegionAndName { public class RegionAndName {
protected final String region; protected final String region;
protected final String name; protected final String name;
public String slashEncode() {
return new StringBuilder(region).append('/').append(name).toString();
}
public RegionAndName(String region, String name) { public RegionAndName(String region, String name) {
this.region = region; this.region = checkNotNull(region, "region");
this.name = name; this.name = checkNotNull(name, "name");
} }
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; return Objects.hashCode(region, name);
int result = 1;
result = prime * result + ((region == null) ? 0 : region.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
} }
@Override @Override
@ -46,20 +53,10 @@ public class RegionAndName {
return true; return true;
if (obj == null) if (obj == null)
return false; return false;
if (getClass() != obj.getClass()) if (!(obj instanceof RegionAndName))
return false; return false;
RegionAndName other = (RegionAndName) obj; RegionAndName other = RegionAndName.class.cast(obj);
if (region == null) { return Objects.equal(region, other.region) && Objects.equal(name, other.name);
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;
} }
public String getRegion() { public String getRegion() {
@ -72,7 +69,45 @@ public class RegionAndName {
@Override @Override
public String toString() { 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.Predicates.not;
import static com.google.common.base.Strings.emptyToNull; import static com.google.common.base.Strings.emptyToNull;
import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Iterables.filter;
import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromValuesOfEmptyString;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -101,11 +102,8 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
if (instance == null || instance.getId() == null) if (instance == null || instance.getId() == null)
return null; return null;
NodeMetadataBuilder builder = new NodeMetadataBuilder(); NodeMetadataBuilder builder = new NodeMetadataBuilder();
builder = buildInstance(instance, builder); builder.name(instance.getTags().get("Name"));
return builder.build(); addMetadataAndParseTagsFromValuesOfEmptyString(builder, instance.getTags());
}
protected NodeMetadataBuilder buildInstance(final RunningInstance instance, NodeMetadataBuilder builder) {
builder.providerId(instance.getId()); builder.providerId(instance.getId());
builder.id(instance.getRegion() + "/" + instance.getId()); builder.id(instance.getRegion() + "/" + instance.getId());
String group = getGroupForInstance(instance); String group = getGroupForInstance(instance);
@ -145,7 +143,7 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
} catch (UncheckedExecutionException e) { } catch (UncheckedExecutionException e) {
logger.debug("error getting image for %s: %s", regionAndName, e); logger.debug("error getting image for %s: %s", regionAndName, e);
} }
return builder; return builder.build();
} }
protected void addCredentialsForInstance(NodeMetadataBuilder builder, RunningInstance instance) { 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.base.Objects.ToStringHelper;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.hash.Hashing;
import com.google.common.primitives.Bytes; import com.google.common.primitives.Bytes;
/** /**
@ -119,7 +120,8 @@ public class EC2TemplateOptions extends TemplateOptions implements Cloneable {
if (noKeyPair) if (noKeyPair)
toString.add("noKeyPair", noKeyPair); toString.add("noKeyPair", noKeyPair);
toString.add("keyPair", keyPair); 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(); ImmutableSet<BlockDeviceMapping> mappings = blockDeviceMappings.build();
if (mappings.size() != 0) if (mappings.size() != 0)
toString.add("blockDeviceMappings", mappings); 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. * under the License.
*/ */
package org.jclouds.ec2.compute.strategy; package org.jclouds.ec2.compute.strategy;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.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.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.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING;
import static org.jclouds.compute.functions.DefaultCredentialsFromImageOrOverridingCredentials.overrideDefaultCredentialsWithOptionsIfPresent; import static org.jclouds.compute.functions.DefaultCredentialsFromImageOrOverridingCredentials.overrideDefaultCredentialsWithOptionsIfPresent;
import static org.jclouds.ec2.compute.util.EC2ComputeUtils.getZoneFromLocationOrNull; 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.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.aws.util.AWSUtils; import org.jclouds.aws.util.AWSUtils;
import org.jclouds.compute.config.CustomizationResponse; import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.strategy.CreateNodesInGroupThenAddToSet; import org.jclouds.compute.strategy.CreateNodesInGroupThenAddToSet;
@ -48,7 +50,7 @@ import org.jclouds.domain.Credentials;
import org.jclouds.domain.LoginCredentials; import org.jclouds.domain.LoginCredentials;
import org.jclouds.ec2.EC2Client; import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.compute.domain.RegionAndName; 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.domain.RunningInstance;
import org.jclouds.ec2.options.RunInstancesOptions; import org.jclouds.ec2.options.RunInstancesOptions;
import org.jclouds.ec2.reference.EC2Constants; 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.annotations.VisibleForTesting;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder; import com.google.common.collect.Maps;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.common.util.concurrent.Atomics;
/** /**
* creates futures that correlate to * creates futures that correlate to
@ -94,27 +94,23 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
final Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata; final Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata;
@VisibleForTesting @VisibleForTesting
final ComputeUtils utils; final ComputeUtils utils;
final InstancePresent instancePresent; final PresentInstances presentInstances;
final LoadingCache<RunningInstance, LoginCredentials> instanceToCredentials; final LoadingCache<RunningInstance, LoginCredentials> instanceToCredentials;
final Map<String, Credentials> credentialStore; final Map<String, Credentials> credentialStore;
final Provider<TemplateBuilder> templateBuilderProvider;
@Inject @Inject
protected EC2CreateNodesInGroupThenAddToSet( protected EC2CreateNodesInGroupThenAddToSet(
EC2Client client, EC2Client client,
@Named("ELASTICIP") @Named("ELASTICIP") LoadingCache<RegionAndName, String> elasticIpCache,
LoadingCache<RegionAndName, String> elasticIpCache,
@Named(TIMEOUT_NODE_RUNNING) Predicate<AtomicReference<NodeMetadata>> nodeRunning, @Named(TIMEOUT_NODE_RUNNING) Predicate<AtomicReference<NodeMetadata>> nodeRunning,
Provider<TemplateBuilder> templateBuilderProvider,
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
InstancePresent instancePresent, Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata, PresentInstances presentInstances, Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
LoadingCache<RunningInstance, LoginCredentials> instanceToCredentials, Map<String, Credentials> credentialStore, LoadingCache<RunningInstance, LoginCredentials> instanceToCredentials,
ComputeUtils utils) { Map<String, Credentials> credentialStore, ComputeUtils utils) {
this.client = checkNotNull(client, "client"); this.client = checkNotNull(client, "client");
this.elasticIpCache = checkNotNull(elasticIpCache, "elasticIpCache"); this.elasticIpCache = checkNotNull(elasticIpCache, "elasticIpCache");
this.nodeRunning = checkNotNull(nodeRunning, "nodeRunning"); this.nodeRunning = checkNotNull(nodeRunning, "nodeRunning");
this.templateBuilderProvider = checkNotNull(templateBuilderProvider, "templateBuilderProvider"); this.presentInstances = checkNotNull(presentInstances, "presentInstances");
this.instancePresent = checkNotNull(instancePresent, "instancePresent");
this.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = checkNotNull( this.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = checkNotNull(
createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
"createKeyPairAndSecurityGroupsAsNeededAndReturncustomize"); "createKeyPairAndSecurityGroupsAsNeededAndReturncustomize");
@ -137,83 +133,83 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
Template mutableTemplate = template.clone(); Template mutableTemplate = template.clone();
Iterable<String> ips = allocateElasticIpsInRegion(count, mutableTemplate); Set<RunningInstance> started = runInstancesAndWarnOnInvisible(group, count, mutableTemplate);
if (started.size() == 0) {
Iterable<? extends RunningInstance> started = createKeyPairAndSecurityGroupsAsNeededThenRunInstances(group, logger.warn("<< unable to start instances(%s)", mutableTemplate);
count, mutableTemplate); return ImmutableMap.of();
}
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()); 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);
} }
assignElasticIpsToInstances(ips, started); /**
* 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);
return utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(mutableTemplate.getOptions(), transform(started, // add an exception for each of the nodes we cannot customize
runningInstanceToNodeMetadata), goodNodes, badNodes, customizationResponses); Set<RegionAndName> invisibleIds = difference(startedIds, visibleIds);
if (invisibleIds.size() > 0) {
logger.warn("<< not api visible instances(%s)", invisibleIds);
}
return started;
} }
protected void populateCredentials(Iterable<? extends RunningInstance> started, TemplateOptions options) { private void populateCredentials(Set<RunningInstance> input, TemplateOptions options) {
LoginCredentials credentials = null; LoginCredentials credentials = null;
for (RunningInstance instance : started) { for (RunningInstance instance : input) {
credentials = instanceToCredentials.apply(instance); credentials = instanceToCredentials.apply(instance);
if (credentials != null) if (credentials != null)
break; break;
} }
credentials = overrideDefaultCredentialsWithOptionsIfPresent(credentials, options); credentials = overrideDefaultCredentialsWithOptionsIfPresent(credentials, options);
if (credentials != null) if (credentials != null)
for (RunningInstance instance : started) for (RegionAndName instance : transform(input, instanceToRegionAndName))
credentialStore.put("node#" + instance.getRegion() + "/" + instance.getId(), credentials); credentialStore.put("node#" + instance.slashEncode(), credentials);
} }
protected Iterable<String> allocateElasticIpsInRegion(int count, Template template) { private void blockUntilRunningAndAssignElasticIpsToInstancesOrPutIntoBadMap(Set<RunningInstance> input,
Map<NodeMetadata, Exception> badNodes) {
Builder<String> ips = ImmutableSet.builder(); Map<RegionAndName, RunningInstance> instancesById = Maps.uniqueIndex(input, instanceToRegionAndName);
if (!autoAllocateElasticIps) for (RegionAndName id : instancesById.keySet()) {
return ips.build(); try {
logger.debug("<< allocating elastic IP instance(%s)", id);
String region = AWSUtils.getRegionFromLocationOrNull(template.getLocation()); String ip = client.getElasticIPAddressServices().allocateAddressInRegion(id.getRegion());
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 // block until instance is running
logger.debug(">> awaiting status running instance(%s)", coordinates); logger.debug(">> awaiting status running instance(%s)", id);
AtomicReference<NodeMetadata> node = Atomics.newReference(runningInstanceToNodeMetadata.apply(startedInstance)); AtomicReference<NodeMetadata> node = newReference(runningInstanceToNodeMetadata
.apply(instancesById.get(id)));
nodeRunning.apply(node); nodeRunning.apply(node);
logger.trace("<< running instance(%s)", coordinates); logger.trace("<< running instance(%s)", id);
logger.debug(">> associating elastic IP %s to instance %s", ip, coordinates); logger.debug(">> associating elastic IP %s to instance %s", ip, id);
client.getElasticIPAddressServices().associateAddressInRegion(region, ip, id); client.getElasticIPAddressServices().associateAddressInRegion(id.getRegion(), ip, id.getName());
logger.trace("<< associated elastic IP %s to instance %s", ip, coordinates); logger.trace("<< associated elastic IP %s to instance %s", ip, id);
// add mapping of instance to ip into the cache // add mapping of instance to ip into the cache
elasticIpCache.put(coordinates, ip); elasticIpCache.put(id, ip);
} catch (RuntimeException e) {
badNodes.put(runningInstanceToNodeMetadata.apply(instancesById.get(id)), e);
}
} }
} }
protected Iterable<? extends RunningInstance> createKeyPairAndSecurityGroupsAsNeededThenRunInstances(String group, private Set<RunningInstance> createKeyPairAndSecurityGroupsAsNeededThenRunInstances(String group, int count,
int count, Template template) { Template template) {
String region = AWSUtils.getRegionFromLocationOrNull(template.getLocation()); String region = AWSUtils.getRegionFromLocationOrNull(template.getLocation());
String zone = getZoneFromLocationOrNull(template.getLocation()); String zone = getZoneFromLocationOrNull(template.getLocation());
RunInstancesOptions instanceOptions = createKeyPairAndSecurityGroupsAsNeededAndReturncustomize.execute(region, RunInstancesOptions instanceOptions = createKeyPairAndSecurityGroupsAsNeededAndReturncustomize.execute(region,
@ -221,21 +217,23 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
return createNodesInRegionAndZone(region, zone, group, count, template, instanceOptions); return createNodesInRegionAndZone(region, zone, group, count, template, instanceOptions);
} }
protected Iterable<? extends RunningInstance> createNodesInRegionAndZone(String region, String zone, String group, protected Set<RunningInstance> createNodesInRegionAndZone(String region, String zone, String group, int count,
int count, Template template, RunInstancesOptions instanceOptions) { Template template, RunInstancesOptions instanceOptions) {
int countStarted = 0; int countStarted = 0;
int tries = 0; int tries = 0;
Iterable<? extends RunningInstance> started = ImmutableSet.<RunningInstance> of(); Set<RunningInstance> started = ImmutableSet.<RunningInstance> of();
while (countStarted < count && tries++ < count) { while (countStarted < count && tries++ < count) {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug(">> running %d instance region(%s) zone(%s) ami(%s) params(%s)", count - countStarted, region, logger.debug(">> running %d instance region(%s) zone(%s) ami(%s) params(%s)", count - countStarted, region,
zone, template.getImage().getProviderId(), instanceOptions.buildFormParameters()); zone, template.getImage().getProviderId(), instanceOptions.buildFormParameters());
started = Iterables.concat(started, client.getInstanceServices().runInstancesInRegion(region, zone, started = ImmutableSet.copyOf(concat(
template.getImage().getProviderId(), 1, count - countStarted, instanceOptions)); started,
client.getInstanceServices().runInstancesInRegion(region, zone, template.getImage().getProviderId(), 1,
count - countStarted, instanceOptions)));
countStarted = Iterables.size(started); countStarted = size(started);
if (countStarted < count) if (countStarted < count)
logger.debug(">> not enough instances (%d/%d) started, attempting again", 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;
import com.google.common.base.Objects.ToStringHelper; import com.google.common.base.Objects.ToStringHelper;
import com.google.common.base.Strings;
import com.google.common.collect.ComparisonChain; import com.google.common.collect.ComparisonChain;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
@ -42,11 +43,18 @@ import com.google.common.collect.Sets;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class RunningInstance implements Comparable<RunningInstance> { public class RunningInstance implements Comparable<RunningInstance> {
public static Builder builder() {
return new Builder(); public static 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 String region;
protected Set<String> groupNames = Sets.newLinkedHashSet(); protected Set<String> groupNames = Sets.newLinkedHashSet();
protected String amiLaunchIndex; protected String amiLaunchIndex;
@ -70,157 +78,174 @@ public class RunningInstance implements Comparable<RunningInstance> {
protected RootDeviceType rootDeviceType = RootDeviceType.INSTANCE_STORE; protected RootDeviceType rootDeviceType = RootDeviceType.INSTANCE_STORE;
protected String rootDeviceName; protected String rootDeviceName;
protected Map<String, BlockDevice> ebsBlockDevices = Maps.newLinkedHashMap(); 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; 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")); this.groupNames = ImmutableSet.copyOf(checkNotNull(groupNames, "groupNames"));
return this; return self();
} }
public Builder groupName(String groupName) { public T groupName(String groupName) {
if (groupName != null) if (groupName != null)
this.groupNames.add(groupName); this.groupNames.add(groupName);
return this; return self();
} }
public Builder amiLaunchIndex(String amiLaunchIndex) { public T amiLaunchIndex(String amiLaunchIndex) {
this.amiLaunchIndex = amiLaunchIndex; this.amiLaunchIndex = amiLaunchIndex;
return this; return self();
} }
public Builder dnsName(String dnsName) { public T dnsName(String dnsName) {
this.dnsName = dnsName; this.dnsName = dnsName;
return this; return self();
} }
public Builder imageId(String imageId) { public T imageId(String imageId) {
this.imageId = imageId; this.imageId = imageId;
return this; return self();
} }
public Builder instanceId(String instanceId) { public T instanceId(String instanceId) {
this.instanceId = instanceId; this.instanceId = instanceId;
return this; return self();
} }
public Builder instanceState(InstanceState instanceState) { public T instanceState(InstanceState instanceState) {
this.instanceState = instanceState; this.instanceState = instanceState;
return this; return self();
} }
public Builder rawState(String rawState) { public T rawState(String rawState) {
this.rawState = rawState; this.rawState = rawState;
return this; return self();
} }
public Builder instanceType(String instanceType) { public T instanceType(String instanceType) {
this.instanceType = instanceType; this.instanceType = instanceType;
return this; return self();
} }
public Builder ipAddress(String ipAddress) { public T ipAddress(String ipAddress) {
this.ipAddress = ipAddress; this.ipAddress = ipAddress;
return this; return self();
} }
public Builder kernelId(String kernelId) { public T kernelId(String kernelId) {
this.kernelId = kernelId; this.kernelId = kernelId;
return this; return self();
} }
public Builder keyName(String keyName) { public T keyName(String keyName) {
this.keyName = keyName; this.keyName = keyName;
return this; return self();
} }
public Builder launchTime(Date launchTime) { public T launchTime(Date launchTime) {
this.launchTime = launchTime; this.launchTime = launchTime;
return this; return self();
} }
public Builder availabilityZone(String availabilityZone) { public T availabilityZone(String availabilityZone) {
this.availabilityZone = availabilityZone; this.availabilityZone = availabilityZone;
return this; return self();
} }
public Builder virtualizationType(String virtualizationType) { public T virtualizationType(String virtualizationType) {
this.virtualizationType = virtualizationType; this.virtualizationType = virtualizationType;
return this; return self();
} }
public Builder platform(String platform) { public T platform(String platform) {
this.platform = platform; this.platform = platform;
return this; return self();
} }
public Builder privateDnsName(String privateDnsName) { public T privateDnsName(String privateDnsName) {
this.privateDnsName = privateDnsName; this.privateDnsName = privateDnsName;
return this; return self();
} }
public Builder privateIpAddress(String privateIpAddress) { public T privateIpAddress(String privateIpAddress) {
this.privateIpAddress = privateIpAddress; this.privateIpAddress = privateIpAddress;
return this; return self();
} }
public Builder ramdiskId(String ramdiskId) { public T ramdiskId(String ramdiskId) {
this.ramdiskId = ramdiskId; this.ramdiskId = ramdiskId;
return this; return self();
} }
public Builder reason(String reason) { public T reason(String reason) {
this.reason = reason; this.reason = reason;
return this; return self();
} }
public Builder rootDeviceType(RootDeviceType rootDeviceType) { public T rootDeviceType(RootDeviceType rootDeviceType) {
this.rootDeviceType = rootDeviceType; this.rootDeviceType = rootDeviceType;
return this; return self();
} }
public Builder rootDeviceName(String rootDeviceName) { public T rootDeviceName(String rootDeviceName) {
this.rootDeviceName = 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")); 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) if (key != null && value != null)
this.ebsBlockDevices.put(key, value); 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; return this;
} }
@Override
public RunningInstance build() { public RunningInstance build() {
return new RunningInstance(region, groupNames, amiLaunchIndex, dnsName, imageId, instanceId, instanceState, return new RunningInstance(region, groupNames, amiLaunchIndex, dnsName, imageId, instanceId, instanceState,
rawState, instanceType, ipAddress, kernelId, keyName, launchTime, availabilityZone, rawState, instanceType, ipAddress, kernelId, keyName, launchTime, availabilityZone, virtualizationType,
virtualizationType, platform, privateDnsName, privateIpAddress, ramdiskId, reason, rootDeviceType, platform, privateDnsName, privateIpAddress, ramdiskId, reason, rootDeviceType, rootDeviceName,
rootDeviceName, ebsBlockDevices); 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; protected final String region;
@ -256,6 +281,7 @@ public class RunningInstance implements Comparable<RunningInstance> {
@Nullable @Nullable
protected final String rootDeviceName; protected final String rootDeviceName;
protected final Map<String, BlockDevice> ebsBlockDevices; protected final Map<String, BlockDevice> ebsBlockDevices;
protected final Map<String, String> tags;
protected RunningInstance(String region, Iterable<String> groupNames, @Nullable String amiLaunchIndex, protected RunningInstance(String region, Iterable<String> groupNames, @Nullable String amiLaunchIndex,
@Nullable String dnsName, String imageId, String instanceId, InstanceState instanceState, String rawState, @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, Date launchTime, String availabilityZone, String virtualizationType, @Nullable String platform,
@Nullable String privateDnsName, @Nullable String privateIpAddress, @Nullable String ramdiskId, @Nullable String privateDnsName, @Nullable String privateIpAddress, @Nullable String ramdiskId,
@Nullable String reason, RootDeviceType rootDeviceType, @Nullable String rootDeviceName, @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.region = checkNotNull(region, "region");
this.amiLaunchIndex = amiLaunchIndex; // nullable on runinstances. this.amiLaunchIndex = amiLaunchIndex; // nullable on runinstances.
this.dnsName = dnsName; // nullable on runinstances. this.dnsName = dnsName; // nullable on runinstances.
@ -287,6 +313,7 @@ public class RunningInstance implements Comparable<RunningInstance> {
this.rootDeviceName = rootDeviceName; this.rootDeviceName = rootDeviceName;
this.ebsBlockDevices = ImmutableMap.copyOf(checkNotNull(ebsBlockDevices, "ebsBlockDevices for %s/%s", region, instanceId)); 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.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; return groupNames;
} }
/**
* tags that are present in the instance
*/
public Map<String, String> getTags() {
return tags;
}
@Override @Override
public int compareTo(RunningInstance other) { public int compareTo(RunningInstance other) {
return ComparisonChain.start().compare(region, other.region).compare(instanceId, other.instanceId, Ordering.natural().nullsLast()).result(); 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("ipAddress", ipAddress).add("dnsName", dnsName).add("privateIpAddress", privateIpAddress)
.add("privateDnsName", privateDnsName).add("keyName", keyName).add("groupNames", groupNames) .add("privateDnsName", privateDnsName).add("keyName", keyName).add("groupNames", groupNames)
.add("platform", platform).add("launchTime", launchTime).add("rootDeviceName", rootDeviceName) .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 @Override

View File

@ -18,6 +18,8 @@
*/ */
package org.jclouds.ec2.reference; package org.jclouds.ec2.reference;
import org.jclouds.compute.ComputeService;
/** /**
* Configuration properties and constants used in EC2 connections. * Configuration properties and constants used in EC2 connections.
* *
@ -40,4 +42,11 @@ public interface EC2Constants {
* deallocate when the node is destroyed. * deallocate when the node is destroyed.
*/ */
public static final String PROPERTY_EC2_AUTO_ALLOCATE_ELASTIC_IPS = "jclouds.ec2.auto-allocate-elastic-ips"; 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.base.Supplier;
import com.google.common.collect.Sets; 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 DateCodec dateCodec;
protected final Supplier<String> defaultRegion; protected final Supplier<String> defaultRegion;
protected final Provider<Builder> builderProvider;
@Inject @Inject
public BaseReservationHandler(DateCodecFactory dateCodecFactory, @Region Supplier<String> defaultRegion, public BaseReservationHandler(DateCodecFactory dateCodecFactory, @Region Supplier<String> defaultRegion) {
Provider<RunningInstance.Builder> builderProvider) {
this.dateCodec = dateCodecFactory.iso8601(); this.dateCodec = dateCodecFactory.iso8601();
this.defaultRegion = defaultRegion; 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 StringBuilder currentText = new StringBuilder();
protected Builder builder;
protected int itemDepth; protected int itemDepth;
protected boolean inInstancesSet; protected boolean inInstancesSet;
protected boolean inProductCodes; protected boolean inProductCodes;
@ -181,13 +187,6 @@ public abstract class BaseReservationHandler<T> extends HandlerForGeneratedReque
currentText = new StringBuilder(); currentText = new StringBuilder();
} }
protected void inItem() {
if (endOfInstanceItem()) {
refineBuilderBeforeAddingInstance();
instances.add(builder.build());
builder = builderProvider.get();
}
}
protected void refineBuilderBeforeAddingInstance() { protected void refineBuilderBeforeAddingInstance() {
String region = getRequest() != null ? AWSUtils.findRegionInArgsOrNull(getRequest()) : null; String region = getRequest() != null ? AWSUtils.findRegionInArgsOrNull(getRequest()) : null;
@ -195,10 +194,6 @@ public abstract class BaseReservationHandler<T> extends HandlerForGeneratedReque
builder.groupNames(groupNames); builder.groupNames(groupNames);
} }
protected Builder builder() {
return builder;
}
protected boolean endOfInstanceItem() { protected boolean endOfInstanceItem() {
return itemDepth <= 2 && inInstancesSet && !inProductCodes && !inGroupSet; return itemDepth <= 2 && inInstancesSet && !inProductCodes && !inGroupSet;
} }

View File

@ -18,6 +18,8 @@
*/ */
package org.jclouds.ec2.xml; package org.jclouds.ec2.xml;
import static org.jclouds.util.SaxUtils.equalsOrSuffix;
import java.util.Set; import java.util.Set;
import javax.inject.Inject; import javax.inject.Inject;
@ -26,10 +28,11 @@ import org.jclouds.date.DateCodecFactory;
import org.jclouds.ec2.domain.Reservation; import org.jclouds.ec2.domain.Reservation;
import org.jclouds.ec2.domain.RunningInstance; import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.location.Region; import org.jclouds.location.Region;
import org.xml.sax.Attributes;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.collect.Sets; import com.google.common.collect.ImmutableSet;
import com.google.inject.Provider; import com.google.common.collect.ImmutableSet.Builder;
/** /**
* Parses the following XML document: * Parses the following XML document:
@ -41,17 +44,52 @@ import com.google.inject.Provider;
*/ */
public class DescribeInstancesResponseHandler extends public class DescribeInstancesResponseHandler extends
BaseReservationHandler<Set<Reservation<? extends RunningInstance>>> { BaseReservationHandler<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;
@Inject @Inject
public DescribeInstancesResponseHandler(DateCodecFactory dateCodecFactory, DescribeInstancesResponseHandler(DateCodecFactory dateCodecFactory, @Region Supplier<String> defaultRegion,
@Region Supplier<String> defaultRegion, Provider<RunningInstance.Builder> builderProvider) { TagSetHandler tagSetHandler) {
super(dateCodecFactory, defaultRegion, builderProvider); 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 @Override
public Set<Reservation<? extends RunningInstance>> getResult() { public Set<Reservation<? extends RunningInstance>> getResult() {
return reservations; return reservations.build();
} }
protected boolean endOfReservationItem() { 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 org.jclouds.location.Region;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.inject.Provider;
/** /**
* Parses the following XML document: * Parses the following XML document:
@ -39,9 +38,8 @@ import com.google.inject.Provider;
public class RunInstancesResponseHandler extends BaseReservationHandler<Reservation<? extends RunningInstance>> { public class RunInstancesResponseHandler extends BaseReservationHandler<Reservation<? extends RunningInstance>> {
@Inject @Inject
public RunInstancesResponseHandler(DateCodecFactory dateCodecFactory, @Region Supplier<String> defaultRegion, public RunInstancesResponseHandler(DateCodecFactory dateCodecFactory, @Region Supplier<String> defaultRegion) {
Provider<RunningInstance.Builder> builderProvider) { super(dateCodecFactory, defaultRegion);
super(dateCodecFactory, defaultRegion, builderProvider);
} }
@Override @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(); return new SshjSshClientModule();
} }
// normal ec2 does not support metadata
@Override @Override
protected void checkUserMetadataContains(NodeMetadata node, ImmutableMap<String, String> userMetadata) { protected void checkUserMetadataContains(NodeMetadata node, ImmutableMap<String, String> userMetadata) {
assert node.getUserMetadata().equals(ImmutableMap.<String, String> of()) : String.format( if (view.unwrap(EC2ApiMetadata.CONTEXT_TOKEN).getApi().getTagApi().isPresent()) {
"node userMetadata did not match %s %s", userMetadata, node); super.checkUserMetadataContains(node, userMetadata);
} else {
assertTrue(node.getUserMetadata().isEmpty(), "not expecting metadata when tag extension isn't present" + node);
}
} }
@Test(enabled = true, dependsOnMethods = "testCorrectAuthException") @Test(enabled = true, dependsOnMethods = "testCorrectAuthException")
public void testImagesResolveCorrectly() { public void testImagesResolveCorrectly() {
@ -324,7 +325,7 @@ public class EC2ComputeServiceLiveTest extends BaseComputeServiceLiveTest {
return instance; return instance;
} }
public static void cleanupExtendedStuffInRegion(String region, SecurityGroupClient securityGroupClient, protected static void cleanupExtendedStuffInRegion(String region, SecurityGroupClient securityGroupClient,
KeyPairClient keyPairClient, String group) throws InterruptedException { KeyPairClient keyPairClient, String group) throws InterruptedException {
try { try {
for (SecurityGroup secgroup : securityGroupClient.describeSecurityGroupsInRegion(region)) 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.NodeMetadata.Status;
import org.jclouds.compute.domain.NodeMetadataBuilder; import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.predicates.AtomicNodeRunning; import org.jclouds.compute.predicates.AtomicNodeRunning;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy; import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import org.jclouds.compute.util.ComputeUtils; import org.jclouds.compute.util.ComputeUtils;
@ -47,9 +46,9 @@ import org.jclouds.domain.LocationScope;
import org.jclouds.domain.LoginCredentials; import org.jclouds.domain.LoginCredentials;
import org.jclouds.ec2.EC2Client; import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.compute.domain.RegionAndName; 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.functions.RunningInstanceToNodeMetadata;
import org.jclouds.ec2.compute.options.EC2TemplateOptions; import org.jclouds.ec2.compute.options.EC2TemplateOptions;
import org.jclouds.ec2.compute.predicates.InstancePresent;
import org.jclouds.ec2.domain.Reservation; import org.jclouds.ec2.domain.Reservation;
import org.jclouds.ec2.domain.RunningInstance; import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.ec2.options.RunInstancesOptions; import org.jclouds.ec2.options.RunInstancesOptions;
@ -62,7 +61,6 @@ import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.inject.util.Providers;
/** /**
* @author Adrian Cole * @author Adrian Cole
@ -81,8 +79,7 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
NodeMetadata nodeMetadata = new NodeMetadataBuilder().id(region + "/" + instanceCreatedId) NodeMetadata nodeMetadata = new NodeMetadataBuilder().id(region + "/" + instanceCreatedId)
.providerId(instanceCreatedId).status(Status.RUNNING).build(); .providerId(instanceCreatedId).status(Status.RUNNING).build();
// setup mocks // setup mocks
TemplateBuilder templateBuilder = createMock(TemplateBuilder.class); EC2CreateNodesInGroupThenAddToSet strategy = setupStrategy(nodeMetadata);
EC2CreateNodesInGroupThenAddToSet strategy = setupStrategy(templateBuilder, nodeMetadata);
InputParams input = new InputParams(location); InputParams input = new InputParams(location);
InstanceClient instanceClient = createMock(InstanceClient.class); InstanceClient instanceClient = createMock(InstanceClient.class);
ElasticIPAddressClient ipClient = createMock(ElasticIPAddressClient.class); ElasticIPAddressClient ipClient = createMock(ElasticIPAddressClient.class);
@ -122,7 +119,7 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
expect(instance.getRegion()).andReturn(region).atLeastOnce(); expect(instance.getRegion()).andReturn(region).atLeastOnce();
expect(strategy.credentialStore.put("node#" + region + "/" + instanceCreatedId, creds)).andReturn(null); expect(strategy.credentialStore.put("node#" + region + "/" + instanceCreatedId, creds)).andReturn(null);
expect(strategy.instancePresent.apply(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.template.getOptions()).andReturn(input.options).atLeastOnce();
expect(input.options.getLoginUser()).andReturn(null); expect(input.options.getLoginUser()).andReturn(null);
expect(input.options.getLoginPassword()).andReturn(null); expect(input.options.getLoginPassword()).andReturn(null);
@ -135,7 +132,6 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
.andReturn(null); .andReturn(null);
// replay mocks // replay mocks
replay(templateBuilder);
replay(instanceClient); replay(instanceClient);
replay(ipClient); replay(ipClient);
replay(ec2Options); replay(ec2Options);
@ -147,7 +143,6 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
strategy.execute(input.tag, input.count, input.template, input.nodes, input.badNodes, input.customization); strategy.execute(input.tag, input.count, input.template, input.nodes, input.badNodes, input.customization);
// verify mocks // verify mocks
verify(templateBuilder);
verify(instanceClient); verify(instanceClient);
verify(ipClient); verify(ipClient);
verify(ec2Options); verify(ec2Options);
@ -195,8 +190,7 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
.providerId(instanceCreatedId).status(Status.RUNNING).build(); .providerId(instanceCreatedId).status(Status.RUNNING).build();
// setup mocks // setup mocks
TemplateBuilder templateBuilder = createMock(TemplateBuilder.class); EC2CreateNodesInGroupThenAddToSet strategy = setupStrategy(nodeMetadata);
EC2CreateNodesInGroupThenAddToSet strategy = setupStrategy(templateBuilder, nodeMetadata);
InputParams input = new InputParams(location); InputParams input = new InputParams(location);
InstanceClient instanceClient = createMock(InstanceClient.class); InstanceClient instanceClient = createMock(InstanceClient.class);
RunInstancesOptions ec2Options = createMock(RunInstancesOptions.class); RunInstancesOptions ec2Options = createMock(RunInstancesOptions.class);
@ -223,7 +217,7 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
expect(instance.getRegion()).andReturn(region).atLeastOnce(); expect(instance.getRegion()).andReturn(region).atLeastOnce();
expect(strategy.credentialStore.put("node#" + region + "/" + instanceCreatedId, creds)).andReturn(null); expect(strategy.credentialStore.put("node#" + region + "/" + instanceCreatedId, creds)).andReturn(null);
expect(strategy.instancePresent.apply(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.template.getOptions()).andReturn(input.options).atLeastOnce();
expect(input.options.getLoginUser()).andReturn(null); expect(input.options.getLoginUser()).andReturn(null);
expect(input.options.getLoginPassword()).andReturn(null); expect(input.options.getLoginPassword()).andReturn(null);
@ -238,7 +232,6 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
.andReturn(null); .andReturn(null);
// replay mocks // replay mocks
replay(templateBuilder);
replay(instanceClient); replay(instanceClient);
replay(ec2Options); replay(ec2Options);
replay(instance); replay(instance);
@ -249,7 +242,6 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
strategy.execute(input.tag, input.count, input.template, input.nodes, input.badNodes, input.customization); strategy.execute(input.tag, input.count, input.template, input.nodes, input.badNodes, input.customization);
// verify mocks // verify mocks
verify(templateBuilder);
verify(instanceClient); verify(instanceClient);
verify(ec2Options); verify(ec2Options);
verify(instance); verify(instance);
@ -307,7 +299,7 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
verify(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize); verify(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize);
verify(strategy.client); verify(strategy.client);
verify(strategy.elasticIpCache); verify(strategy.elasticIpCache);
verify(strategy.instancePresent); verify(strategy.presentInstances);
verify(strategy.runningInstanceToNodeMetadata); verify(strategy.runningInstanceToNodeMetadata);
verify(strategy.instanceToCredentials); verify(strategy.instanceToCredentials);
verify(strategy.credentialStore); verify(strategy.credentialStore);
@ -315,10 +307,10 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private EC2CreateNodesInGroupThenAddToSet setupStrategy(TemplateBuilder template, final NodeMetadata node) { private EC2CreateNodesInGroupThenAddToSet setupStrategy(final NodeMetadata node) {
EC2Client client = createMock(EC2Client.class); EC2Client client = createMock(EC2Client.class);
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = createMock(CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.class); CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = createMock(CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.class);
InstancePresent instancePresent = createMock(InstancePresent.class); PresentInstances presentInstances = createMock(PresentInstances.class);
RunningInstanceToNodeMetadata runningInstanceToNodeMetadata = createMock(RunningInstanceToNodeMetadata.class); RunningInstanceToNodeMetadata runningInstanceToNodeMetadata = createMock(RunningInstanceToNodeMetadata.class);
LoadingCache<RunningInstance, LoginCredentials> instanceToCredentials = createMock(LoadingCache.class); LoadingCache<RunningInstance, LoginCredentials> instanceToCredentials = createMock(LoadingCache.class);
LoadingCache<RegionAndName, String> elasticIpCache = createMock(LoadingCache.class); LoadingCache<RegionAndName, String> elasticIpCache = createMock(LoadingCache.class);
@ -334,15 +326,15 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
Map<String, Credentials> credentialStore = createMock(Map.class); Map<String, Credentials> credentialStore = createMock(Map.class);
ComputeUtils utils = createMock(ComputeUtils.class); ComputeUtils utils = createMock(ComputeUtils.class);
return new EC2CreateNodesInGroupThenAddToSet(client, elasticIpCache, new AtomicNodeRunning(nodeRunning), return new EC2CreateNodesInGroupThenAddToSet(client, elasticIpCache, new AtomicNodeRunning(nodeRunning),
Providers.<TemplateBuilder> of(template), createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, presentInstances, runningInstanceToNodeMetadata,
instancePresent, runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils); instanceToCredentials, credentialStore, utils);
} }
private void replayStrategy(EC2CreateNodesInGroupThenAddToSet strategy) { private void replayStrategy(EC2CreateNodesInGroupThenAddToSet strategy) {
replay(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize); replay(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize);
replay(strategy.client); replay(strategy.client);
replay(strategy.elasticIpCache); replay(strategy.elasticIpCache);
replay(strategy.instancePresent); replay(strategy.presentInstances);
replay(strategy.runningInstanceToNodeMetadata); replay(strategy.runningInstanceToNodeMetadata);
replay(strategy.instanceToCredentials); replay(strategy.instanceToCredentials);
replay(strategy.credentialStore); 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.Supplier;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Guice; import com.google.inject.Guice;
@ -69,7 +70,7 @@ public class DescribeInstancesResponseHandlerTest extends BaseEC2HandlerTest {
public void testWhenRunning() throws UnknownHostException { public void testWhenRunning() throws UnknownHostException {
Set<Reservation<RunningInstance>> contents = ImmutableSet.of(new Reservation<RunningInstance>(defaultRegion, 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( defaultRegion).groupName("adriancole.ec2ingress").amiLaunchIndex("0").dnsName(
"ec2-174-129-81-68.compute-1.amazonaws.com").imageId("ami-82e4b5c7").instanceId("i-0799056f") "ec2-174-129-81-68.compute-1.amazonaws.com").imageId("ami-82e4b5c7").instanceId("i-0799056f")
.instanceState(InstanceState.RUNNING).rawState("running").instanceType(InstanceType.M1_SMALL) .instanceState(InstanceState.RUNNING).rawState("running").instanceType(InstanceType.M1_SMALL)
@ -91,7 +92,7 @@ public class DescribeInstancesResponseHandlerTest extends BaseEC2HandlerTest {
public void testApplyInputStream() { public void testApplyInputStream() {
Set<Reservation<RunningInstance>> contents = ImmutableSet.of(new Reservation<RunningInstance>(defaultRegion, 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( "default").amiLaunchIndex("23").dnsName("ec2-72-44-33-4.compute-1.amazonaws.com").imageId(
"ami-6ea54007").instanceId("i-28a64341").instanceState(InstanceState.RUNNING).rawState( "ami-6ea54007").instanceId("i-28a64341").instanceState(InstanceState.RUNNING).rawState(
"running").instanceType(InstanceType.M1_LARGE).kernelId("aki-ba3adfd3").keyName( "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( .availabilityZone("us-east-1b").virtualizationType("paravirtual").privateDnsName(
"10-251-50-132.ec2.internal")// product codes "10-251-50-132.ec2.internal")// product codes
// ImmutableSet.of("774F4FF8") // ImmutableSet.of("774F4FF8")
.tags(ImmutableMap.of("Name","ec2-o", "Empty",""))
.ramdiskId("ari-badbad00").rootDeviceType(RootDeviceType.INSTANCE_STORE).build(), .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( .dnsName("ec2-72-44-33-6.compute-1.amazonaws.com").imageId("ami-6ea54007").instanceId(
"i-28a64435").instanceState(InstanceState.RUNNING).rawState("running") "i-28a64435").instanceState(InstanceState.RUNNING).rawState("running")
.instanceType(InstanceType.M1_LARGE).kernelId("aki-ba3adfd3").keyName( .instanceType(InstanceType.M1_LARGE).kernelId("aki-ba3adfd3").keyName(
@ -125,7 +127,7 @@ public class DescribeInstancesResponseHandlerTest extends BaseEC2HandlerTest {
public void testEBS() throws UnknownHostException { public void testEBS() throws UnknownHostException {
Set<Reservation<RunningInstance>> contents = ImmutableSet.of(new Reservation<RunningInstance>(defaultRegion, 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( defaultRegion).groupName("adriancole.ec2ebsingress").amiLaunchIndex("0").dnsName(
"ec2-75-101-203-146.compute-1.amazonaws.com").imageId("ami-849875ed").instanceId("i-e564438d") "ec2-75-101-203-146.compute-1.amazonaws.com").imageId("ami-849875ed").instanceId("i-e564438d")
.instanceState(InstanceState.RUNNING).rawState("running").instanceType(InstanceType.M1_SMALL) .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 Reservation<? extends RunningInstance> expected = new Reservation<RunningInstance>(defaultRegion, ImmutableSet
.of("default"), ImmutableSet.of( .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( .imageId("ami-60a54009").instanceId("i-2ba64342").instanceState(InstanceState.PENDING).rawState(
"pending").instanceType(InstanceType.M1_SMALL).keyName("example-key-name").launchTime( "pending").instanceType(InstanceType.M1_SMALL).keyName("example-key-name").launchTime(
dateService.iso8601DateParse("2007-08-07T11:51:50.000Z"))// MonitoringState.ENABLED, dateService.iso8601DateParse("2007-08-07T11:51:50.000Z"))// MonitoringState.ENABLED,
.availabilityZone("us-east-1b").build(), .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( .imageId("ami-60a54009").instanceId("i-2bc64242").instanceState(InstanceState.PENDING).rawState(
"pending").instanceType(InstanceType.M1_SMALL).keyName("example-key-name").launchTime( "pending").instanceType(InstanceType.M1_SMALL).keyName("example-key-name").launchTime(
dateService.iso8601DateParse("2007-08-07T11:51:50.000Z"))// MonitoringState.ENABLED, dateService.iso8601DateParse("2007-08-07T11:51:50.000Z"))// MonitoringState.ENABLED,
.availabilityZone("us-east-1b").build(), .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( .imageId("ami-60a54009").instanceId("i-2be64332").instanceState(InstanceState.PENDING).rawState(
"pending").instanceType(InstanceType.M1_SMALL).keyName("example-key-name").launchTime( "pending").instanceType(InstanceType.M1_SMALL).keyName("example-key-name").launchTime(
dateService.iso8601DateParse("2007-08-07T11:51:50.000Z"))// MonitoringState.ENABLED, 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 Reservation<? extends RunningInstance> expected = new Reservation<RunningInstance>(defaultRegion, ImmutableSet
.of("jclouds#greenqloud-computeblock"), ImmutableSet.of( .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( .imageId("qmi-9ac92558").instanceId("i-01b0dac3").instanceState(InstanceState.PENDING).rawState(
"pending").instanceType(InstanceType.M1_SMALL).keyName("jclouds#greenqloud-computeblock#35") "pending").instanceType(InstanceType.M1_SMALL).keyName("jclouds#greenqloud-computeblock#35")
.launchTime(dateService.iso8601DateParse("2012-06-15T19:06:35.000+00:00")) .launchTime(dateService.iso8601DateParse("2012-06-15T19:06:35.000+00:00"))

View File

@ -38,6 +38,16 @@
<kernelId>aki-ba3adfd3</kernelId> <kernelId>aki-ba3adfd3</kernelId>
<ramdiskId>ari-badbad00</ramdiskId> <ramdiskId>ari-badbad00</ramdiskId>
<hypervisor>xen</hypervisor> <hypervisor>xen</hypervisor>
<tagSet>
<item>
<key>Name</key>
<value>ec2-o</value>
</item>
<item>
<key>Empty</key>
<value />
</item>
</tagSet>
</item> </item>
<item> <item>
<instanceId>i-28a64435</instanceId> <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.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.concurrent.TimeUnit.SECONDS;
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX; 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 static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_AMI_OWNERS;
import java.util.Properties; import java.util.Properties;
@ -66,13 +65,11 @@ public class AWSEC2ApiMetadata extends EC2ApiMetadata {
Properties properties = EC2ApiMetadata.defaultProperties(); Properties properties = EC2ApiMetadata.defaultProperties();
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", SECONDS.toMillis(90) + ""); properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", SECONDS.toMillis(90) + "");
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "SpotInstanceClient.describeSpotPriceHistoryInRegion", MINUTES.toMillis(2) + ""); properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "SpotInstanceClient.describeSpotPriceHistoryInRegion", MINUTES.toMillis(2) + "");
properties.remove(PROPERTY_EC2_AMI_OWNERS); properties.remove(PROPERTY_EC2_AMI_OWNERS);
// auth fail sometimes happens in EC2, as the rc.local script that injects the // auth fail sometimes happens in EC2, as the rc.local script that injects the
// authorized key executes after ssh has started. // authorized key executes after ssh has started.
properties.setProperty("jclouds.ssh.max-retries", "7"); properties.setProperty("jclouds.ssh.max-retries", "7");
properties.setProperty("jclouds.ssh.retry-auth", "true"); properties.setProperty("jclouds.ssh.retry-auth", "true");
properties.setProperty(PROPERTY_EC2_GENERATE_INSTANCE_NAMES, "true");
return properties; 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.MonitoringAsyncClient;
import org.jclouds.aws.ec2.services.PlacementGroupAsyncClient; import org.jclouds.aws.ec2.services.PlacementGroupAsyncClient;
import org.jclouds.aws.ec2.services.SpotInstanceAsyncClient; import org.jclouds.aws.ec2.services.SpotInstanceAsyncClient;
import org.jclouds.aws.ec2.services.TagAsyncClient;
import org.jclouds.ec2.EC2AsyncClient; import org.jclouds.ec2.EC2AsyncClient;
import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.Delegate;
@ -82,10 +81,4 @@ public interface AWSEC2AsyncClient extends EC2AsyncClient {
*/ */
@Delegate @Delegate
SpotInstanceAsyncClient getSpotInstanceServices(); 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.MonitoringClient;
import org.jclouds.aws.ec2.services.PlacementGroupClient; import org.jclouds.aws.ec2.services.PlacementGroupClient;
import org.jclouds.aws.ec2.services.SpotInstanceClient; import org.jclouds.aws.ec2.services.SpotInstanceClient;
import org.jclouds.aws.ec2.services.TagClient;
import org.jclouds.ec2.EC2Client; import org.jclouds.ec2.EC2Client;
import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.Delegate;
@ -81,10 +80,4 @@ public interface AWSEC2Client extends EC2Client {
*/ */
@Delegate @Delegate
SpotInstanceClient getSpotInstanceServices(); SpotInstanceClient getSpotInstanceServices();
/**
* Provides synchronous access to Tag services.
*/
@Delegate
TagClient getTagServices();
} }

View File

@ -18,13 +18,11 @@
*/ */
package org.jclouds.aws.ec2.compute; 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.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_RUNNING;
import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; 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.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED;
import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_GENERATE_INSTANCE_NAMES;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -38,20 +36,15 @@ import javax.inject.Provider;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.aws.ec2.AWSEC2AsyncClient;
import org.jclouds.aws.ec2.AWSEC2Client; import org.jclouds.aws.ec2.AWSEC2Client;
import org.jclouds.aws.ec2.domain.PlacementGroup; import org.jclouds.aws.ec2.domain.PlacementGroup;
import org.jclouds.aws.ec2.domain.PlacementGroup.State; import org.jclouds.aws.ec2.domain.PlacementGroup.State;
import org.jclouds.aws.util.AWSUtils;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.callables.RunScriptOnNode; import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.extensions.ImageExtension; import org.jclouds.compute.extensions.ImageExtension;
import org.jclouds.compute.functions.GroupNamingConvention; import org.jclouds.compute.functions.GroupNamingConvention;
@ -71,20 +64,15 @@ import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.ec2.compute.EC2ComputeService; import org.jclouds.ec2.compute.EC2ComputeService;
import org.jclouds.ec2.compute.domain.RegionAndName; import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.compute.options.EC2TemplateOptions;
import org.jclouds.ec2.domain.KeyPair; import org.jclouds.ec2.domain.KeyPair;
import org.jclouds.scriptbuilder.functions.InitAdminAccess; import org.jclouds.scriptbuilder.functions.InitAdminAccess;
import org.jclouds.util.Preconditions2; import org.jclouds.util.Preconditions2;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
/** /**
* @author Adrian Cole * @author Adrian Cole
@ -94,9 +82,7 @@ public class AWSEC2ComputeService extends EC2ComputeService {
private final LoadingCache<RegionAndName, String> placementGroupMap; private final LoadingCache<RegionAndName, String> placementGroupMap;
private final Predicate<PlacementGroup> placementGroupDeleted; private final Predicate<PlacementGroup> placementGroupDeleted;
private final AWSEC2Client ec2Client; private final AWSEC2Client client;
private final AWSEC2AsyncClient aclient;
private final boolean generateInstanceNames;
@Inject @Inject
protected AWSEC2ComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore, protected AWSEC2ComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore,
@ -113,77 +99,22 @@ public class AWSEC2ComputeService extends EC2ComputeService {
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, AWSEC2Client ec2Client, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, AWSEC2Client client,
ConcurrentMap<RegionAndName, KeyPair> credentialsMap, ConcurrentMap<RegionAndName, KeyPair> credentialsMap,
@Named("SECURITY") LoadingCache<RegionAndName, String> securityGroupMap, @Named("SECURITY") LoadingCache<RegionAndName, String> securityGroupMap,
@Named("PLACEMENT") LoadingCache<RegionAndName, String> placementGroupMap, @Named("PLACEMENT") LoadingCache<RegionAndName, String> placementGroupMap,
@Named("DELETED") Predicate<PlacementGroup> placementGroupDeleted, @Named("DELETED") Predicate<PlacementGroup> placementGroupDeleted, Optional<ImageExtension> imageExtension,
@Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean generateInstanceNames, AWSEC2AsyncClient aclient, 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, super(context, credentialStore, images, sizes, locations, listNodesStrategy, getImageStrategy,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy,
stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, startNodeStrategy, stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning,
nodeSuspended, initScriptRunnerFactory, runScriptOnNodeFactory, initAdminAccess, persistNodeCredentials, nodeTerminated, nodeSuspended, initScriptRunnerFactory, runScriptOnNodeFactory, initAdminAccess,
timeouts, executor, ec2Client, credentialsMap, securityGroupMap, imageExtension, namingConvention); persistNodeCredentials, timeouts, executor, client, credentialsMap, securityGroupMap, imageExtension,
this.ec2Client = ec2Client; namingConvention, generateInstanceNames);
this.client = client;
this.placementGroupMap = placementGroupMap; this.placementGroupMap = placementGroupMap;
this.placementGroupDeleted = placementGroupDeleted; 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 @VisibleForTesting
@ -193,10 +124,10 @@ public class AWSEC2ComputeService extends EC2ComputeService {
// http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/index.html?using_cluster_computing.html // http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/index.html?using_cluster_computing.html
String placementGroup = String.format("jclouds#%s#%s", group, region); String placementGroup = String.format("jclouds#%s#%s", group, region);
try { try {
if (ec2Client.getPlacementGroupServices().describePlacementGroupsInRegion(region, placementGroup).size() > 0) { if (client.getPlacementGroupServices().describePlacementGroupsInRegion(region, placementGroup).size() > 0) {
logger.debug(">> deleting placementGroup(%s)", placementGroup); logger.debug(">> deleting placementGroup(%s)", placementGroup);
try { try {
ec2Client.getPlacementGroupServices().deletePlacementGroupInRegion(region, placementGroup); client.getPlacementGroupServices().deletePlacementGroupInRegion(region, placementGroup);
checkState(placementGroupDeleted.apply(new PlacementGroup(region, placementGroup, "cluster", checkState(placementGroupDeleted.apply(new PlacementGroup(region, placementGroup, "cluster",
State.PENDING)), String.format("placementGroup region(%s) name(%s) failed to delete", region, State.PENDING)), String.format("placementGroup region(%s) name(%s) failed to delete", region,
placementGroup)); 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 @Override
public EC2TemplateOptions templateOptions() { public AWSEC2TemplateOptions templateOptions() {
return EC2TemplateOptions.class.cast(super.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.AWSEC2TemplateBuilderImpl;
import org.jclouds.aws.ec2.compute.functions.AWSRunningInstanceToNodeMetadata; 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.AWSEC2CreateNodesInGroupThenAddToSet;
import org.jclouds.aws.ec2.compute.strategy.AWSEC2DestroyNodeStrategy; import org.jclouds.aws.ec2.compute.strategy.AWSEC2DestroyNodeStrategy;
import org.jclouds.aws.ec2.compute.strategy.AWSEC2GetNodeMetadataStrategy; 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.compute.options.TemplateOptions;
import org.jclouds.ec2.compute.config.EC2BindComputeStrategiesByClass; import org.jclouds.ec2.compute.config.EC2BindComputeStrategiesByClass;
import org.jclouds.ec2.compute.domain.RegionAndName; 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.functions.RunningInstanceToNodeMetadata;
import org.jclouds.ec2.compute.internal.EC2TemplateBuilderImpl; import org.jclouds.ec2.compute.internal.EC2TemplateBuilderImpl;
import org.jclouds.ec2.compute.loaders.RegionAndIdToImage; import org.jclouds.ec2.compute.loaders.RegionAndIdToImage;
import org.jclouds.ec2.compute.options.EC2TemplateOptions; import org.jclouds.ec2.compute.options.EC2TemplateOptions;
import org.jclouds.ec2.compute.predicates.InstancePresent;
import org.jclouds.ec2.compute.strategy.CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions; import org.jclouds.ec2.compute.strategy.CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions;
import org.jclouds.ec2.compute.strategy.EC2CreateNodesInGroupThenAddToSet; import org.jclouds.ec2.compute.strategy.EC2CreateNodesInGroupThenAddToSet;
import org.jclouds.ec2.compute.strategy.EC2DestroyNodeStrategy; import org.jclouds.ec2.compute.strategy.EC2DestroyNodeStrategy;
@ -92,7 +92,7 @@ public class AWSEC2ComputeServiceContextModule extends BaseComputeServiceContext
bind(EC2GetNodeMetadataStrategy.class).to(AWSEC2GetNodeMetadataStrategy.class); bind(EC2GetNodeMetadataStrategy.class).to(AWSEC2GetNodeMetadataStrategy.class);
bind(EC2ListNodesStrategy.class).to(AWSEC2ListNodesStrategy.class); bind(EC2ListNodesStrategy.class).to(AWSEC2ListNodesStrategy.class);
bind(EC2DestroyNodeStrategy.class).to(AWSEC2DestroyNodeStrategy.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(EC2CreateNodesInGroupThenAddToSet.class).to(AWSEC2CreateNodesInGroupThenAddToSet.class);
bind(RunningInstanceToNodeMetadata.class).to(AWSRunningInstanceToNodeMetadata.class); bind(RunningInstanceToNodeMetadata.class).to(AWSRunningInstanceToNodeMetadata.class);
} }

View File

@ -18,8 +18,6 @@
*/ */
package org.jclouds.aws.ec2.compute.functions; package org.jclouds.aws.ec2.compute.functions;
import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromValuesOfEmptyString;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -31,8 +29,8 @@ import org.jclouds.collect.Memoized;
import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.HardwareBuilder; import org.jclouds.compute.domain.HardwareBuilder;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.NodeMetadata.Status; import org.jclouds.compute.domain.NodeMetadata.Status;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.functions.GroupNamingConvention; import org.jclouds.compute.functions.GroupNamingConvention;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
@ -82,11 +80,4 @@ public class AWSRunningInstanceToNodeMetadata extends RunningInstanceToNodeMetad
return HardwareBuilder.fromHardware(in).hypervisor(awsInstance.getHypervisor().toString()).build(); 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; package org.jclouds.aws.ec2.compute.strategy;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.transform; 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_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.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.aws.ec2.AWSEC2AsyncClient;
import org.jclouds.aws.ec2.AWSEC2Client; import org.jclouds.aws.ec2.AWSEC2Client;
import org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions; import org.jclouds.aws.ec2.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.domain.LaunchSpecification;
import org.jclouds.aws.ec2.functions.SpotInstanceRequestToAWSRunningInstance; import org.jclouds.aws.ec2.functions.SpotInstanceRequestToAWSRunningInstance;
import org.jclouds.aws.ec2.options.AWSRunInstancesOptions; import org.jclouds.aws.ec2.options.AWSRunInstancesOptions;
import org.jclouds.aws.ec2.options.RequestSpotInstancesOptions; import org.jclouds.aws.ec2.options.RequestSpotInstancesOptions;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.util.ComputeUtils; 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.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
/** /**
@ -70,39 +66,33 @@ public class AWSEC2CreateNodesInGroupThenAddToSet extends EC2CreateNodesInGroupT
@Resource @Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER) @Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL; private Logger logger = Logger.NULL;
@VisibleForTesting @VisibleForTesting
final AWSEC2Client client; private final AWSEC2Client client;
final SpotInstanceRequestToAWSRunningInstance spotConverter; private final SpotInstanceRequestToAWSRunningInstance spotConverter;
final AWSEC2AsyncClient aclient;
final boolean generateInstanceNames;
@Inject @Inject
protected AWSEC2CreateNodesInGroupThenAddToSet( protected AWSEC2CreateNodesInGroupThenAddToSet(
AWSEC2Client client, AWSEC2Client client,
@Named("ELASTICIP") LoadingCache<RegionAndName, String> elasticIpCache, @Named("ELASTICIP") LoadingCache<RegionAndName, String> elasticIpCache,
@Named(TIMEOUT_NODE_RUNNING) Predicate<AtomicReference<NodeMetadata>> nodeRunning, @Named(TIMEOUT_NODE_RUNNING) Predicate<AtomicReference<NodeMetadata>> nodeRunning,
AWSEC2AsyncClient aclient,
@Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean generateInstanceNames, @Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean generateInstanceNames,
Provider<TemplateBuilder> templateBuilderProvider,
CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
AWSEC2InstancePresent instancePresent, PresentSpotRequestsAndInstances instancePresent,
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata, Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
LoadingCache<RunningInstance, LoginCredentials> instanceToCredentials, Map<String, Credentials> credentialStore, LoadingCache<RunningInstance, LoginCredentials> instanceToCredentials,
ComputeUtils utils, SpotInstanceRequestToAWSRunningInstance spotConverter) { Map<String, Credentials> credentialStore, ComputeUtils utils,
super(client, elasticIpCache, nodeRunning, templateBuilderProvider, createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, SpotInstanceRequestToAWSRunningInstance spotConverter) {
super(client, elasticIpCache, nodeRunning, createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
instancePresent, runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils); instancePresent, runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils);
this.client = checkNotNull(client, "client"); this.client = checkNotNull(client, "client");
this.aclient = checkNotNull(aclient, "aclient");
this.spotConverter = checkNotNull(spotConverter, "spotConverter"); this.spotConverter = checkNotNull(spotConverter, "spotConverter");
this.generateInstanceNames = generateInstanceNames;
} }
@Override @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) { int count, Template template, RunInstancesOptions instanceOptions) {
Map<String, String> tags = metadataAndTagsAsValuesOfEmptyString(template.getOptions());
Float spotPrice = getSpotPriceOrNull(template.getOptions()); Float spotPrice = getSpotPriceOrNull(template.getOptions());
if (spotPrice != null) { if (spotPrice != null) {
LaunchSpecification spec = AWSRunInstancesOptions.class.cast(instanceOptions).getLaunchSpecificationBuilder() LaunchSpecification spec = AWSRunInstancesOptions.class.cast(instanceOptions).getLaunchSpecificationBuilder()
@ -111,36 +101,10 @@ public class AWSEC2CreateNodesInGroupThenAddToSet extends EC2CreateNodesInGroupT
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug(">> requesting %d spot instances region(%s) price(%f) spec(%s) options(%s)", count, region, logger.debug(">> requesting %d spot instances region(%s) price(%f) spec(%s) options(%s)", count, region,
spotPrice, spec, options); spotPrice, spec, options);
return addTagsToInstancesInRegion(tags, transform(client return ImmutableSet.<RunningInstance> copyOf(transform(client.getSpotInstanceServices()
.getSpotInstanceServices().requestSpotInstancesInRegion(region, spotPrice, count, spec, options), .requestSpotInstancesInRegion(region, spotPrice, count, spec, options), spotConverter));
spotConverter), region, group);
} else {
return addTagsToInstancesInRegion(tags, super.createNodesInRegionAndZone(
region, zone, group, count, template, instanceOptions), region, group);
} }
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) { private Float getSpotPriceOrNull(TemplateOptions options) {

View File

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

View File

@ -32,7 +32,6 @@ import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
import com.google.common.base.Objects.ToStringHelper; import com.google.common.base.Objects.ToStringHelper;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
@ -46,11 +45,17 @@ import com.google.common.collect.Sets;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class AWSRunningInstance extends RunningInstance { public class AWSRunningInstance extends RunningInstance {
public static Builder builder() { public static Builder builder() {
return new 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 MonitoringState monitoringState;
private String placementGroup; private String placementGroup;
private Set<String> productCodes = Sets.newLinkedHashSet(); private Set<String> productCodes = Sets.newLinkedHashSet();
@ -59,18 +64,6 @@ public class AWSRunningInstance extends RunningInstance {
private String vpcId; private String vpcId;
private Hypervisor hypervisor; private Hypervisor hypervisor;
private Map<String, String> securityGroupIdToNames = Maps.newLinkedHashMap(); 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) { public Builder securityGroupIdToNames(Map<String, String> securityGroupIdToNames) {
this.securityGroupIdToNames = ImmutableMap.copyOf(checkNotNull(securityGroupIdToNames, this.securityGroupIdToNames = ImmutableMap.copyOf(checkNotNull(securityGroupIdToNames,
@ -125,131 +118,6 @@ public class AWSRunningInstance extends RunningInstance {
return this; 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 @Override
public AWSRunningInstance build() { public AWSRunningInstance build() {
return new AWSRunningInstance(region, securityGroupIdToNames, amiLaunchIndex, dnsName, imageId, instanceId, return new AWSRunningInstance(region, securityGroupIdToNames, amiLaunchIndex, dnsName, imageId, instanceId,
@ -259,6 +127,24 @@ public class AWSRunningInstance extends RunningInstance {
spotInstanceRequestId, vpcId, hypervisor, tags); 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;
}
} }
private final MonitoringState monitoringState; private final MonitoringState monitoringState;
@ -273,7 +159,6 @@ public class AWSRunningInstance extends RunningInstance {
private final String vpcId; private final String vpcId;
private final Hypervisor hypervisor; private final Hypervisor hypervisor;
private final Map<String, String> securityGroupIdToNames; private final Map<String, String> securityGroupIdToNames;
private final Map<String, String> tags;
protected AWSRunningInstance(String region, Map<String, String> securityGroupIdToNames, String amiLaunchIndex, protected AWSRunningInstance(String region, Map<String, String> securityGroupIdToNames, String amiLaunchIndex,
String dnsName, String imageId, String instanceId, InstanceState instanceState, String rawState, 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, super(region, securityGroupIdToNames.values(), amiLaunchIndex, dnsName, imageId, instanceId, instanceState,
rawState, instanceType, ipAddress, kernelId, keyName, launchTime, availabilityZone, virtualizationType, rawState, instanceType, ipAddress, kernelId, keyName, launchTime, availabilityZone, virtualizationType,
platform, privateDnsName, privateIpAddress, ramdiskId, reason, rootDeviceType, rootDeviceName, platform, privateDnsName, privateIpAddress, ramdiskId, reason, rootDeviceType, rootDeviceName,
ebsBlockDevices); ebsBlockDevices, tags);
this.monitoringState = checkNotNull(monitoringState, "monitoringState"); this.monitoringState = checkNotNull(monitoringState, "monitoringState");
this.placementGroup = placementGroup; this.placementGroup = placementGroup;
this.productCodes = ImmutableSet.copyOf(checkNotNull(productCodes, "productCodes")); this.productCodes = ImmutableSet.copyOf(checkNotNull(productCodes, "productCodes"));
@ -296,7 +181,6 @@ public class AWSRunningInstance extends RunningInstance {
this.hypervisor = checkNotNull(hypervisor, "hypervisor"); this.hypervisor = checkNotNull(hypervisor, "hypervisor");
this.securityGroupIdToNames = ImmutableMap.<String, String> copyOf(checkNotNull(securityGroupIdToNames, this.securityGroupIdToNames = ImmutableMap.<String, String> copyOf(checkNotNull(securityGroupIdToNames,
"securityGroupIdToNames")); "securityGroupIdToNames"));
this.tags = ImmutableMap.<String, String> copyOf(checkNotNull(tags, "tags"));
} }
public Map<String, String> getSecurityGroupIdToNames() { public Map<String, String> getSecurityGroupIdToNames() {
@ -356,18 +240,11 @@ public class AWSRunningInstance extends RunningInstance {
return subnetId; return subnetId;
} }
/**
* tags that are present in the instance
*/
public Map<String, String> getTags() {
return tags;
}
@Override @Override
protected ToStringHelper string() { protected ToStringHelper string() {
return super.string().add("monitoringState", monitoringState).add("placementGroup", placementGroup) return super.string().add("monitoringState", monitoringState).add("placementGroup", placementGroup)
.add("subnetId", subnetId).add("spotInstanceRequestId", spotInstanceRequestId).add("vpcId", vpcId) .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; package org.jclouds.aws.ec2.functions;
import javax.inject.Singleton;
import org.jclouds.aws.ec2.domain.AWSRunningInstance; import org.jclouds.aws.ec2.domain.AWSRunningInstance;
import org.jclouds.aws.ec2.domain.LaunchSpecification; import org.jclouds.aws.ec2.domain.LaunchSpecification;
import org.jclouds.aws.ec2.domain.MonitoringState; import org.jclouds.aws.ec2.domain.MonitoringState;
@ -32,7 +30,6 @@ import com.google.common.base.Function;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton
public class SpotInstanceRequestToAWSRunningInstance implements Function<SpotInstanceRequest, AWSRunningInstance> { public class SpotInstanceRequestToAWSRunningInstance implements Function<SpotInstanceRequest, AWSRunningInstance> {
@Override @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_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_CC_REGIONS = "jclouds.ec2.cc-regions";
public static final String PROPERTY_EC2_AMI_QUERY = "jclouds.ec2.ami-query"; 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; package org.jclouds.aws.ec2.xml;
import static org.jclouds.util.SaxUtils.currentOrNull;
import static org.jclouds.util.SaxUtils.equalsOrSuffix; import static org.jclouds.util.SaxUtils.equalsOrSuffix;
import java.util.Set; import java.util.Set;
import javax.inject.Inject; import javax.inject.Inject;
import org.jclouds.aws.ec2.domain.AWSRunningInstance;
import org.jclouds.date.DateCodecFactory; import org.jclouds.date.DateCodecFactory;
import org.jclouds.ec2.domain.Reservation; import org.jclouds.ec2.domain.Reservation;
import org.jclouds.ec2.domain.RunningInstance; import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.ec2.xml.TagSetHandler;
import org.jclouds.location.Region; import org.jclouds.location.Region;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.collect.Sets; import com.google.common.collect.ImmutableSet;
import com.google.inject.Provider; import com.google.common.collect.ImmutableSet.Builder;
/** /**
* Parses the following XML document: * Parses the following XML document:
@ -47,42 +46,51 @@ import com.google.inject.Provider;
*/ */
public class AWSDescribeInstancesResponseHandler extends public class AWSDescribeInstancesResponseHandler extends
BaseAWSReservationHandler<Set<Reservation<? extends RunningInstance>>> { 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 boolean inTagSet;
private String key;
private String value;
@Inject @Inject
AWSDescribeInstancesResponseHandler(DateCodecFactory dateCodecFactory, @Region Supplier<String> defaultRegion, AWSDescribeInstancesResponseHandler(DateCodecFactory dateCodecFactory, @Region Supplier<String> defaultRegion,
Provider<AWSRunningInstance.Builder> builderProvider, TagSetHandler tagSetHandler) { TagSetHandler tagSetHandler) {
super(dateCodecFactory, defaultRegion, builderProvider); super(dateCodecFactory, defaultRegion);
this.tagSetHandler = tagSetHandler;
} }
@Override @Override
public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException { public void startElement(String uri, String name, String qName, Attributes attrs) throws SAXException {
super.startElement(uri, localName, qName, attrs); super.startElement(uri, name, qName, attrs);
if (equalsOrSuffix(qName, "tagSet")) { if (equalsOrSuffix(qName, "tagSet")) {
inTagSet = true; 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 @Override
public void endElement(String uri, String name, String qName) { public void endElement(String uri, String name, String qName) {
if (equalsOrSuffix(qName, "tagSet")) { if (equalsOrSuffix(qName, "tagSet")) {
inTagSet = false; inTagSet = false;
builder.tags(tagSetHandler.getResult());
} else if (inTagSet) { } else if (inTagSet) {
if (equalsOrSuffix(qName, "key")) { tagSetHandler.endElement(uri, name, qName);
key = currentOrNull(currentText);
} else if (equalsOrSuffix(qName, "value")) {
value = currentOrNull(currentText);
}
} }
super.endElement(uri, name, qName); super.endElement(uri, name, qName);
} }
@Override @Override
public Set<Reservation<? extends RunningInstance>> getResult() { public Set<Reservation<? extends RunningInstance>> getResult() {
return reservations; return reservations.build();
} }
protected boolean endOfReservationItem() { protected boolean endOfReservationItem() {
@ -93,10 +101,6 @@ public class AWSDescribeInstancesResponseHandler extends
protected void inItem() { protected void inItem() {
if (endOfReservationItem()) { if (endOfReservationItem()) {
reservations.add(super.newReservation()); reservations.add(super.newReservation());
} else if (inTagSet) {
builder.tag(key, value);
key = null;
value = null;
} else { } else {
super.inItem(); super.inItem();
} }

View File

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

View File

@ -49,7 +49,6 @@ import org.xml.sax.SAXException;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Sets; 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 DateCodec dateCodec;
protected final Supplier<String> defaultRegion; protected final Supplier<String> defaultRegion;
protected final Provider<AWSRunningInstance.Builder> builderProvider;
@Inject @Inject
public BaseAWSReservationHandler(DateCodecFactory dateCodecFactory, @Region Supplier<String> defaultRegion, public BaseAWSReservationHandler(DateCodecFactory dateCodecFactory, @Region Supplier<String> defaultRegion) {
Provider<AWSRunningInstance.Builder> builderProvider) {
this.dateCodec = dateCodecFactory.iso8601(); this.dateCodec = dateCodecFactory.iso8601();
this.defaultRegion = defaultRegion; 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 StringBuilder currentText = new StringBuilder();
protected AWSRunningInstance.Builder builder;
protected int itemDepth; protected int itemDepth;
boolean inInstancesSet; boolean inInstancesSet;
// attachments // attachments
@ -215,7 +214,7 @@ public abstract class BaseAWSReservationHandler<T> extends HandlerForGeneratedRe
if (endOfInstanceItem()) { if (endOfInstanceItem()) {
refineBuilderBeforeAddingInstance(); refineBuilderBeforeAddingInstance();
instances.add(builder.build()); 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.aws.util.AWSUtils;
import org.jclouds.date.DateCodec; import org.jclouds.date.DateCodec;
import org.jclouds.date.DateCodecFactory; import org.jclouds.date.DateCodecFactory;
import org.jclouds.ec2.xml.TagSetHandler;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.location.Region; import org.jclouds.location.Region;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;

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.getSecurityGroupServices() != null;
assert syncClient.getPlacementGroupServices() != null; assert syncClient.getPlacementGroupServices() != null;
assert syncClient.getWindowsServices() != 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.getSecurityGroupServices() != null;
assert asyncClient.getPlacementGroupServices() != null; assert asyncClient.getPlacementGroupServices() != null;
assert asyncClient.getWindowsServices() != null; assert asyncClient.getWindowsServices() != null;
assert asyncClient.getTagServices() != null;
} }
@BeforeClass @BeforeClass

View File

@ -77,13 +77,6 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
group = "ec2"; 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 @Override
@Test @Test
public void testExtendedOptionsAndLogin() throws Exception { public void testExtendedOptionsAndLogin() throws Exception {
@ -103,12 +96,14 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest {
Date before = new Date(); Date before = new Date();
ImmutableMap<String, String> userMetadata = ImmutableMap.<String, String> of("test", group); 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 // 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 template = client.templateBuilder().locationId(region).osFamily(AMZN_LINUX).os64Bit(true).build();
template.getOptions().tags(tags); template.getOptions().tags(tags);
template.getOptions().userMetadata(userMetadata); template.getOptions().userMetadata(userMetadata);
template.getOptions().tags(tags);
template.getOptions().as(AWSEC2TemplateOptions.class).enableMonitoring(); template.getOptions().as(AWSEC2TemplateOptions.class).enableMonitoring();
template.getOptions().as(AWSEC2TemplateOptions.class).spotPrice(0.3f); 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); Set<? extends NodeMetadata> nodes = client.createNodesInGroup(group, 1, template);
NodeMetadata first = getOnlyElement(nodes); NodeMetadata first = getOnlyElement(nodes);
// Name metadata should turn into node.name
assertEquals(first.getName(), group);
checkUserMetadataContains(first, userMetadata); checkUserMetadataContains(first, userMetadata);
checkTagsInNodeEquals(first, tags); 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)));
}
}