Issue 130: added location and made compute service set-based

git-svn-id: http://jclouds.googlecode.com/svn/trunk@2730 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
adrian.f.cole 2010-01-28 05:21:11 +00:00
parent 70aa7e4ef3
commit 3521c47029
82 changed files with 2431 additions and 1570 deletions

View File

@ -19,9 +19,10 @@
package org.jclouds.aws.ec2; package org.jclouds.aws.ec2;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.aws.ec2.reference.EC2Constants.PROPERTY_EC2_AMI_OWNERS;
import static org.jclouds.aws.ec2.reference.EC2Constants.PROPERTY_EC2_ENDPOINT; import static org.jclouds.aws.ec2.reference.EC2Constants.PROPERTY_EC2_ENDPOINT;
import static org.jclouds.aws.ec2.reference.EC2Constants.PROPERTY_AWS_EXPIREINTERVAL;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AWS_ACCESSKEYID; import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AWS_ACCESSKEYID;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AWS_EXPIREINTERVAL;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AWS_SECRETACCESSKEY; import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AWS_SECRETACCESSKEY;
import java.net.URI; import java.net.URI;
@ -40,6 +41,7 @@ public class EC2PropertiesBuilder extends PropertiesBuilder {
Properties properties = super.defaultProperties(); Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_EC2_ENDPOINT, "https://ec2.us-east-1.amazonaws.com"); properties.setProperty(PROPERTY_EC2_ENDPOINT, "https://ec2.us-east-1.amazonaws.com");
properties.setProperty(PROPERTY_AWS_EXPIREINTERVAL, "60"); properties.setProperty(PROPERTY_AWS_EXPIREINTERVAL, "60");
properties.setProperty(PROPERTY_EC2_AMI_OWNERS, "063491364108");
return properties; return properties;
} }

View File

@ -21,11 +21,12 @@ package org.jclouds.aws.ec2.compute;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.withKeyName; import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.withKeyName;
import static org.jclouds.compute.util.ComputeUtils.METADATA_TO_ID;
import java.net.InetAddress;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
@ -33,39 +34,46 @@ import javax.inject.Named;
import javax.inject.Provider; import javax.inject.Provider;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.aws.AWSResponseException; import org.jclouds.Constants;
import org.jclouds.aws.domain.Region; import org.jclouds.aws.domain.Region;
import org.jclouds.aws.ec2.EC2Client; import org.jclouds.aws.ec2.EC2Client;
import org.jclouds.aws.ec2.compute.domain.EC2Image;
import org.jclouds.aws.ec2.compute.domain.EC2Size; import org.jclouds.aws.ec2.compute.domain.EC2Size;
import org.jclouds.aws.ec2.compute.domain.KeyPairCredentials;
import org.jclouds.aws.ec2.compute.domain.PortsRegionTag;
import org.jclouds.aws.ec2.compute.domain.RegionTag;
import org.jclouds.aws.ec2.compute.functions.CreateKeyPairIfNeeded;
import org.jclouds.aws.ec2.compute.functions.CreateSecurityGroupIfNeeded;
import org.jclouds.aws.ec2.compute.functions.RunningInstanceToNodeMetadata;
import org.jclouds.aws.ec2.domain.AvailabilityZone;
import org.jclouds.aws.ec2.domain.InstanceState; import org.jclouds.aws.ec2.domain.InstanceState;
import org.jclouds.aws.ec2.domain.IpProtocol; import org.jclouds.aws.ec2.domain.Reservation;
import org.jclouds.aws.ec2.domain.KeyPair;
import org.jclouds.aws.ec2.domain.RunningInstance; import org.jclouds.aws.ec2.domain.RunningInstance;
import org.jclouds.aws.ec2.options.RunInstancesOptions; import org.jclouds.aws.ec2.options.RunInstancesOptions;
import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeService;
import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.ComputeType; import org.jclouds.compute.domain.ComputeType;
import org.jclouds.compute.domain.CreateNodeResponse;
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.NodeSet;
import org.jclouds.compute.domain.NodeState; import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.Size; import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.domain.internal.ComputeMetadataImpl; import org.jclouds.compute.domain.internal.NodeSetImpl;
import org.jclouds.compute.domain.internal.CreateNodeResponseImpl; import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.domain.internal.NodeMetadataImpl;
import org.jclouds.compute.options.RunNodeOptions;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.Credentials; import org.jclouds.concurrent.ConcurrentUtils;
import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.internal.ImmutableSet; import com.google.inject.internal.ImmutableSet;
/** /**
@ -73,128 +81,129 @@ import com.google.inject.internal.ImmutableSet;
*/ */
@Singleton @Singleton
public class EC2ComputeService implements ComputeService { public class EC2ComputeService implements ComputeService {
private static Function<RunningInstance, String> instanceToId = new Function<RunningInstance, String>() {
@Override
public String apply(RunningInstance from) {
return from.getId();
}
};
private static class NodeMatchesTag implements Predicate<NodeMetadata> {
private final String tag;
@Override
public boolean apply(NodeMetadata from) {
return from.getTag().equals(tag);
}
public NodeMatchesTag(String tag) {
super();
this.tag = tag;
}
};
@Resource @Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER) @Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
private final EC2Client ec2Client; protected final EC2Client ec2Client;
protected final Provider<Set<? extends Image>> images; protected final Map<RegionTag, KeyPairCredentials> credentialsMap;
protected final Provider<Set<? extends Size>> sizes; protected final Map<PortsRegionTag, String> securityGroupMap;
protected final Provider<Map<String, ? extends Image>> images;
protected final Provider<Map<String, ? extends Size>> sizes;
protected final Provider<Map<String, ? extends Location>> locations;
protected final CreateKeyPairIfNeeded createKeyPairIfNeeded;
protected final CreateSecurityGroupIfNeeded createSecurityGroupIfNeeded;
protected final Provider<TemplateBuilder> templateBuilderProvider; protected final Provider<TemplateBuilder> templateBuilderProvider;
private final Predicate<RunningInstance> instanceStateRunning; protected final Predicate<RunningInstance> instanceStateRunning;
private final Predicate<RunningInstance> instanceStateTerminated; protected final Predicate<RunningInstance> instanceStateTerminated;
private final RunningInstanceToNodeMetadata runningInstanceToNodeMetadata; protected final RunningInstanceToNodeMetadata runningInstanceToNodeMetadata;
protected final ExecutorService executor;
@Inject @Inject
public EC2ComputeService(EC2Client client, Provider<TemplateBuilder> templateBuilderProvider, public EC2ComputeService(EC2Client client, Provider<TemplateBuilder> templateBuilderProvider,
Provider<Set<? extends Image>> images, Provider<Set<? extends Size>> sizes, Provider<Map<String, ? extends Image>> images,
Provider<Map<String, ? extends Size>> sizes,
Provider<Map<String, ? extends Location>> locations,
Map<RegionTag, KeyPairCredentials> credentialsMap,
Map<PortsRegionTag, String> securityGroupMap,
CreateKeyPairIfNeeded createKeyPairIfNeeded,
CreateSecurityGroupIfNeeded createSecurityGroupIfNeeded,
@Named("RUNNING") Predicate<RunningInstance> instanceStateRunning, @Named("RUNNING") Predicate<RunningInstance> instanceStateRunning,
@Named("TERMINATED") Predicate<RunningInstance> instanceStateTerminated, @Named("TERMINATED") Predicate<RunningInstance> instanceStateTerminated,
RunningInstanceToNodeMetadata runningInstanceToNodeMetadata) { RunningInstanceToNodeMetadata runningInstanceToNodeMetadata,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
this.templateBuilderProvider = templateBuilderProvider;
this.ec2Client = client; this.ec2Client = client;
this.images = images; this.images = images;
this.sizes = sizes; this.sizes = sizes;
this.templateBuilderProvider = templateBuilderProvider; this.locations = locations;
this.credentialsMap = credentialsMap;
this.createKeyPairIfNeeded = createKeyPairIfNeeded;
this.createSecurityGroupIfNeeded = createSecurityGroupIfNeeded;
this.securityGroupMap = securityGroupMap;
this.instanceStateRunning = instanceStateRunning; this.instanceStateRunning = instanceStateRunning;
this.instanceStateTerminated = instanceStateTerminated; this.instanceStateTerminated = instanceStateTerminated;
this.runningInstanceToNodeMetadata = runningInstanceToNodeMetadata; this.runningInstanceToNodeMetadata = runningInstanceToNodeMetadata;
} this.executor = executor;
private static Map<InstanceState, NodeState> instanceToNodeState = ImmutableMap
.<InstanceState, NodeState> builder().put(InstanceState.PENDING, NodeState.PENDING)
.put(InstanceState.RUNNING, NodeState.RUNNING).put(InstanceState.SHUTTING_DOWN,
NodeState.PENDING).put(InstanceState.TERMINATED, NodeState.TERMINATED).build();
@Override
public CreateNodeResponse runNode(String name, Template template) {
return this.runNode(name, template, RunNodeOptions.NONE);
} }
@Override @Override
public CreateNodeResponse runNode(String name, Template template, RunNodeOptions options) { public NodeSet runNodes(String tag, int count, Template template) {
checkArgument(template.getImage() instanceof EC2Image, checkArgument(tag.indexOf('-') == -1, "tag cannot contain hyphens");
"unexpected image type. should be EC2Image, was: " + template.getImage().getClass());
checkArgument(template.getSize() instanceof EC2Size, checkArgument(template.getSize() instanceof EC2Size,
"unexpected image type. should be EC2Size, was: " + template.getSize().getClass()); "unexpected image type. should be EC2Size, was: " + template.getSize().getClass());
EC2Image ec2Image = EC2Image.class.cast(template.getImage());
EC2Size ec2Size = EC2Size.class.cast(template.getSize()); EC2Size ec2Size = EC2Size.class.cast(template.getSize());
Region region = ec2Image.getImage().getRegion(); // parse the availability zone of the request
KeyPair keyPair = createKeyPairInRegion(region, name); AvailabilityZone zone = template.getLocation().getScope() == LocationScope.ZONE ? AvailabilityZone
String securityGroupName = name; .fromValue(template.getLocation().getId())
createSecurityGroupInRegion(region, securityGroupName, options.getOpenPorts()); : null;
logger.debug(">> running instance region(%s) ami(%s) type(%s) keyPair(%s) securityGroup(%s)", // if the location has a parent, it must be an availability zone.
region, ec2Image.getId(), ec2Size.getInstanceType(), keyPair.getKeyName(), Region region = zone == null ? Region.fromValue(template.getLocation().getId()) : Region
securityGroupName); .fromValue(template.getLocation().getParent());
RunInstancesOptions instanceOptions = withKeyName(keyPair.getKeyName())// key
// get or create incidental resources
// TODO race condition. we were using MapMaker, but it doesn't seem to refresh properly when
// another thread
// deletes a key
RegionTag regionTag = new RegionTag(region, tag);
if (!credentialsMap.containsKey(regionTag)) {
credentialsMap.put(regionTag, createKeyPairIfNeeded.apply(regionTag));
}
TemplateOptions options = template.getOptions();
PortsRegionTag portsRegionTag = new PortsRegionTag(region, tag, options.getInboundPorts());
if (!securityGroupMap.containsKey(portsRegionTag)) {
securityGroupMap.put(portsRegionTag, createSecurityGroupIfNeeded.apply(portsRegionTag));
}
logger
.debug(
">> running %d instance region(%s) zone(%s) ami(%s) type(%s) keyPair(%s) securityGroup(%s)",
count, region, zone, template.getImage().getId(),
ec2Size.getInstanceType(), tag, tag);
RunInstancesOptions instanceOptions = withKeyName(tag)// key
.asType(ec2Size.getInstanceType())// instance size .asType(ec2Size.getInstanceType())// instance size
.withSecurityGroup(securityGroupName)// group I created above .withSecurityGroup(tag)// group I created above
.withAdditionalInfo(name); .withAdditionalInfo(tag);
if (options.getRunScript() != null) if (options.getRunScript() != null)
instanceOptions.withUserData(options.getRunScript()); instanceOptions.withUserData(options.getRunScript());
RunningInstance runningInstance = Iterables.getOnlyElement(ec2Client.getInstanceServices() Reservation reservation = ec2Client.getInstanceServices().runInstancesInRegion(region, zone,
.runInstancesInRegion(region, null, ec2Image.getId(), 1, 1, instanceOptions)); template.getImage().getId(), 1, count, instanceOptions);
logger.debug("<< started instance(%s)", runningInstance.getId()); Iterable<String> ids = Iterables.transform(reservation, instanceToId);
instanceStateRunning.apply(runningInstance);
logger.debug("<< running instance(%s)", runningInstance.getId()); String idsString = Joiner.on(',').join(ids);
logger.debug("<< started instances(%s)", idsString);
Iterables.all(reservation, instanceStateRunning);
logger.debug("<< running instances(%s)", idsString);
// refresh to get IP address // refresh to get IP address
runningInstance = getOnlyRunningInstanceInRegion(region, runningInstance.getId()); return new NodeSetImpl(Iterables.transform(Iterables.concat(ec2Client.getInstanceServices()
.describeInstancesInRegion(region, Iterables.toArray(ids, String.class))),
Set<InetAddress> publicAddresses = runningInstance.getIpAddress() == null ? ImmutableSet runningInstanceToNodeMetadata));
.<InetAddress> of() : ImmutableSet.<InetAddress> of(runningInstance.getIpAddress());
Set<InetAddress> privateAddresses = runningInstance.getPrivateIpAddress() == null ? ImmutableSet
.<InetAddress> of()
: ImmutableSet.<InetAddress> of(runningInstance.getPrivateIpAddress());
return new CreateNodeResponseImpl(runningInstance.getId(), name, runningInstance.getRegion()
.toString(), null, ImmutableMap.<String, String> of(), instanceToNodeState
.get(runningInstance.getInstanceState()), publicAddresses, privateAddresses,
new Credentials("root", keyPair.getKeyMaterial()), ImmutableMap
.<String, String> of());
}
private KeyPair createKeyPairInRegion(Region region, String name) {
logger.debug(">> creating keyPair region(%s) name(%s)", region, name);
KeyPair keyPair;
try {
keyPair = ec2Client.getKeyPairServices().createKeyPairInRegion(region, name);
logger.debug("<< created keyPair(%s)", keyPair.getKeyName());
} catch (AWSResponseException e) {
if (e.getError().getCode().equals("InvalidKeyPair.Duplicate")) {
keyPair = Iterables.getLast(ec2Client.getKeyPairServices().describeKeyPairsInRegion(
region, name));
logger.debug("<< reused keyPair(%s)", keyPair.getKeyName());
} else {
throw e;
}
}
return keyPair;
}
private void createSecurityGroupInRegion(Region region, String name, int... ports) {
logger.debug(">> creating securityGroup region(%s) name(%s)", region, name);
try {
ec2Client.getSecurityGroupServices().createSecurityGroupInRegion(region, name, name);
logger.debug("<< created securityGroup(%s)", name);
for (int port : ports) {
logger.debug(">> authorizing securityGroup region(%s) name(%s) port(%s)", region, name,
port);
ec2Client.getSecurityGroupServices().authorizeSecurityGroupIngressInRegion(region,
name, IpProtocol.TCP, port, port, "0.0.0.0/0");
logger.debug("<< authorized securityGroup(%s)", name);
}
} catch (AWSResponseException e) {
if (e.getError().getCode().equals("InvalidGroup.Duplicate")) {
logger.debug("<< reused securityGroup(%s)", name);
} else {
throw e;
}
}
} }
@Override @Override
@ -208,114 +217,132 @@ public class EC2ComputeService implements ComputeService {
return runningInstanceToNodeMetadata.apply(runningInstance); return runningInstanceToNodeMetadata.apply(runningInstance);
} }
@Singleton
private static class RunningInstanceToNodeMetadata implements
Function<RunningInstance, NodeMetadata> {
@Override
public NodeMetadata apply(RunningInstance from) {
return new NodeMetadataImpl(from.getId(), from.getKeyName(), from.getRegion().toString(),
null, ImmutableMap.<String, String> of(), instanceToNodeState.get(from
.getInstanceState()), nullSafeSet(from.getIpAddress()), nullSafeSet(from
.getPrivateIpAddress()), ImmutableMap.<String, String> of(
"availabilityZone", from.getAvailabilityZone().toString()));
}
Set<InetAddress> nullSafeSet(InetAddress in) {
if (in == null) {
return ImmutableSet.<InetAddress> of();
}
return ImmutableSet.<InetAddress> of(in);
}
}
private RunningInstance getOnlyRunningInstanceInRegion(Region region, String id) {
Iterable<RunningInstance> instances = Iterables.filter(getAllRunningInstancesInRegion(region,
id), new Predicate<RunningInstance>() {
@Override
public boolean apply(RunningInstance instance) {
return instance.getInstanceState() == InstanceState.PENDING
|| instance.getInstanceState() == InstanceState.RUNNING;
}
});
int size = Iterables.size(instances);
if (size == 0)
throw new NoSuchElementException(String.format(
"%d instances in region %s have an instance with id %s running.", size, region,
id));
if (size > 1)
throw new IllegalStateException(String.format(
"%d instances in region %s have an instance with id %s running. Expected 1",
size, region, id));
return Iterables.getOnlyElement(instances);
}
private Iterable<RunningInstance> getAllRunningInstancesInRegion(Region region, String id) { private Iterable<RunningInstance> getAllRunningInstancesInRegion(Region region, String id) {
return Iterables return Iterables
.concat(ec2Client.getInstanceServices().describeInstancesInRegion(region, id)); .concat(ec2Client.getInstanceServices().describeInstancesInRegion(region, id));
} }
/**
* hack alert. can't find a good place to store the original servername, so we are reusing the
* keyname. This will break.
*/
@Override @Override
public Set<ComputeMetadata> listNodes() { public Map<String, NodeMetadata> getNodes() {
logger.debug(">> listing servers"); logger.debug(">> listing servers");
Set<ComputeMetadata> servers = Sets.newHashSet(); Map<String, NodeMetadata> nodes = doGetNodes();
logger.debug("<< list(%d)", nodes.size());
return nodes;
}
protected Map<String, NodeMetadata> doGetNodes() {
Set<NodeMetadata> nodes = Sets.newHashSet();
for (Region region : ImmutableSet.of(Region.US_EAST_1, Region.US_WEST_1, Region.EU_WEST_1)) { for (Region region : ImmutableSet.of(Region.US_EAST_1, Region.US_WEST_1, Region.EU_WEST_1)) {
Iterables.addAll(servers, Iterables.transform(Iterables.concat(ec2Client Iterables.addAll(nodes, Iterables.transform(Iterables.concat(ec2Client
.getInstanceServices().describeInstancesInRegion(region)), .getInstanceServices().describeInstancesInRegion(region)),
new Function<RunningInstance, ComputeMetadata>() { runningInstanceToNodeMetadata));
@Override
public ComputeMetadata apply(RunningInstance from) {
return new ComputeMetadataImpl(ComputeType.NODE, from.getId(), from
.getKeyName(), from.getRegion().toString(), null, ImmutableMap
.<String, String> of());
} }
})); return Maps.uniqueIndex(nodes, METADATA_TO_ID);
}
logger.debug("<< list(%d)", servers.size());
return servers;
} }
@Override @Override
public void destroyNode(ComputeMetadata node) { public void destroyNode(ComputeMetadata metadata) {
checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not " checkArgument(metadata.getType() == ComputeType.NODE, "this is only valid for nodes, not "
+ node.getType()); + metadata.getType());
checkNotNull(node.getId(), "node.id"); checkNotNull(metadata.getId(), "node.id");
NodeMetadata node = metadata instanceof NodeMetadata ? NodeMetadata.class.cast(metadata)
: getNodeMetadata(metadata);
String tag = checkNotNull(node.getTag(), "node.tag");
Region region = getRegionFromNodeOrDefault(node); Region region = getRegionFromNodeOrDefault(node);
for (RunningInstance runningInstance : getAllRunningInstancesInRegion(region, node.getId())) {
// grab the old keyname RunningInstance instance = getInstance(node, region);
String name = runningInstance.getKeyName(); if (instance.getInstanceState() != InstanceState.TERMINATED) {
logger.debug(">> terminating instance(%s)", node.getId()); logger.debug(">> terminating instance(%s)", node.getId());
boolean success = false;
while (!success) {
ec2Client.getInstanceServices().terminateInstancesInRegion(region, node.getId()); ec2Client.getInstanceServices().terminateInstancesInRegion(region, node.getId());
boolean success = instanceStateTerminated.apply(runningInstance); success = instanceStateTerminated.apply(getInstance(node, region));
}
logger.debug("<< terminated instance(%s) success(%s)", node.getId(), success); logger.debug("<< terminated instance(%s) success(%s)", node.getId(), success);
logger.debug(">> deleting keyPair(%s)", name); }
ec2Client.getKeyPairServices().deleteKeyPairInRegion(region, name); if (Iterables.all(doGetNodes(tag), new Predicate<NodeMetadata>() {
logger.debug("<< deleted keyPair(%s)", name); @Override
logger.debug(">> deleting securityGroup(%s)", name); public boolean apply(NodeMetadata input) {
ec2Client.getSecurityGroupServices().deleteSecurityGroupInRegion(region, name); return input.getState() == NodeState.TERMINATED;
logger.debug("<< deleted securityGroup(%s)", name); }
})) {
deleteKeyPair(region, tag);
deleteSecurityGroup(region, tag);
}
}
private RunningInstance getInstance(NodeMetadata node, Region region) {
return Iterables.getOnlyElement(getAllRunningInstancesInRegion(region, node.getId()));
}
private void deleteSecurityGroup(Region region, String tag) {
if (ec2Client.getSecurityGroupServices().describeSecurityGroupsInRegion(region, tag).size() > 0) {
logger.debug(">> deleting securityGroup(%s)", tag);
ec2Client.getSecurityGroupServices().deleteSecurityGroupInRegion(region, tag);
securityGroupMap.remove(new PortsRegionTag(region, tag, null)); // TODO: test this clear
// happens
logger.debug("<< deleted securityGroup(%s)", tag);
}
}
private void deleteKeyPair(Region region, String tag) {
if (ec2Client.getKeyPairServices().describeKeyPairsInRegion(region, tag).size() > 0) {
logger.debug(">> deleting keyPair(%s)", tag);
ec2Client.getKeyPairServices().deleteKeyPairInRegion(region, tag);
credentialsMap.remove(new RegionTag(region, tag)); // TODO: test this clear happens
logger.debug("<< deleted keyPair(%s)", tag);
} }
} }
private Region getRegionFromNodeOrDefault(ComputeMetadata node) { private Region getRegionFromNodeOrDefault(ComputeMetadata node) {
Region region = node.getLocation() != null ? Region.fromValue(node.getLocation()) Location location = getLocations().get(node.getLocationId());
: Region.DEFAULT; Region region = location.getScope() == LocationScope.REGION ? Region.fromValue(location
.getId()) : Region.fromValue(location.getParent());
return region; return region;
} }
@Override @Override
public Set<? extends Size> listSizes() { public void destroyNodes(String tag) { // TODO parallel
logger.debug(">> terminating servers by tag(%s)", tag);
Set<ListenableFuture<Void>> responses = Sets.newHashSet();
for (final NodeMetadata node : doGetNodes(tag)) {
responses.add(ConcurrentUtils.makeListenable(executor.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
destroyNode(node);
return null;
}
}), executor));
}
ConcurrentUtils.awaitCompletion(responses, executor, null, logger, "nodes");
logger.debug("<< destroyed");
}
@Override
public Map<String, ? extends Location> getLocations() {
return locations.get();
}
@Override
public NodeSet getNodes(String tag) {
logger.debug(">> listing servers by tag(%s)", tag);
NodeSet nodes = doGetNodes(tag);
logger.debug("<< list(%d)", nodes.size());
return nodes;
}
protected NodeSet doGetNodes(String tag) {
return new NodeSetImpl(Iterables.filter(doGetNodes().values(), new NodeMatchesTag(tag)));
}
@Override
public Map<String, ? extends Size> getSizes() {
return sizes.get(); return sizes.get();
} }
@Override @Override
public Set<? extends Image> listImages() { public Map<String, ? extends Image> getImages() {
return images.get(); return images.get();
} }

View File

@ -19,6 +19,7 @@
package org.jclouds.aws.ec2.compute.config; package org.jclouds.aws.ec2.compute.config;
import static org.jclouds.aws.ec2.options.DescribeImagesOptions.Builder.ownedBy; import static org.jclouds.aws.ec2.options.DescribeImagesOptions.Builder.ownedBy;
import static org.jclouds.aws.ec2.reference.EC2Constants.PROPERTY_EC2_AMI_OWNERS;
import java.net.URI; import java.net.URI;
import java.util.Map; import java.util.Map;
@ -37,21 +38,36 @@ import org.jclouds.aws.ec2.EC2;
import org.jclouds.aws.ec2.EC2AsyncClient; import org.jclouds.aws.ec2.EC2AsyncClient;
import org.jclouds.aws.ec2.EC2Client; import org.jclouds.aws.ec2.EC2Client;
import org.jclouds.aws.ec2.compute.EC2ComputeService; import org.jclouds.aws.ec2.compute.EC2ComputeService;
import org.jclouds.aws.ec2.compute.domain.EC2Image;
import org.jclouds.aws.ec2.compute.domain.EC2Size; import org.jclouds.aws.ec2.compute.domain.EC2Size;
import org.jclouds.aws.ec2.compute.domain.KeyPairCredentials;
import org.jclouds.aws.ec2.compute.domain.PortsRegionTag;
import org.jclouds.aws.ec2.compute.domain.RegionTag;
import org.jclouds.aws.ec2.compute.functions.CreateKeyPairIfNeeded;
import org.jclouds.aws.ec2.compute.functions.CreateSecurityGroupIfNeeded;
import org.jclouds.aws.ec2.config.EC2ContextModule; import org.jclouds.aws.ec2.config.EC2ContextModule;
import org.jclouds.aws.ec2.domain.AvailabilityZone;
import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.domain.Architecture;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.Size; import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.internal.ImageImpl;
import org.jclouds.compute.internal.ComputeServiceContextImpl; import org.jclouds.compute.internal.ComputeServiceContextImpl;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.ResourceLocation; import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope;
import org.jclouds.domain.internal.LocationImpl;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.RestContext; import org.jclouds.rest.RestContext;
import com.google.common.base.Function;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.inject.Provides; import com.google.inject.Provides;
@ -68,6 +84,22 @@ public class EC2ComputeServiceContextModule extends EC2ContextModule {
bind(ComputeService.class).to(EC2ComputeService.class).asEagerSingleton(); bind(ComputeService.class).to(EC2ComputeService.class).asEagerSingleton();
} }
@Provides
@Singleton
protected final Map<RegionTag, KeyPairCredentials> credentialsMap(CreateKeyPairIfNeeded in) {
// doesn't seem to clear when someone issues remove(key)
// return new MapMaker().makeComputingMap(in);
return Maps.newLinkedHashMap();
}
@Provides
@Singleton
protected final Map<PortsRegionTag, String> securityGroupMap(CreateSecurityGroupIfNeeded in) {
// doesn't seem to clear when someone issues remove(key)
// return new MapMaker().makeComputingMap(in);
return Maps.newLinkedHashMap();
}
@Provides @Provides
@Singleton @Singleton
ComputeServiceContext provideContext(ComputeService computeService, ComputeServiceContext provideContext(ComputeService computeService,
@ -77,16 +109,47 @@ public class EC2ComputeServiceContextModule extends EC2ContextModule {
@Provides @Provides
@Singleton @Singleton
Set<? extends Size> provideSizes() { Function<ComputeMetadata, String> indexer() {
return ImmutableSet.of(EC2Size.C1_MEDIUM, EC2Size.C1_XLARGE, EC2Size.M1_LARGE, return new Function<ComputeMetadata, String>() {
EC2Size.M1_SMALL, EC2Size.M1_XLARGE, EC2Size.M2_2XLARGE, EC2Size.M2_4XLARGE); @Override
public String apply(ComputeMetadata from) {
return from.getId();
}
};
} }
@Provides @Provides
@Singleton @Singleton
@ResourceLocation Map<String, ? extends Size> provideSizes(Function<ComputeMetadata, String> indexer) {
String getRegion(@EC2 Region region) { return Maps.uniqueIndex(ImmutableSet.of(EC2Size.C1_MEDIUM, EC2Size.C1_XLARGE,
return region.value(); EC2Size.M1_LARGE, EC2Size.M1_SMALL, EC2Size.M1_XLARGE, EC2Size.M2_2XLARGE,
EC2Size.M2_4XLARGE), indexer);
}
@Provides
@Singleton
Map<String, ? extends Location> provideLocations(Map<AvailabilityZone, Region> map) {
Set<Location> locations = Sets.newHashSet();
for (AvailabilityZone zone : map.keySet()) {
locations.add(new LocationImpl(LocationScope.ZONE, zone.toString(), zone.toString(), map
.get(zone).toString(), true));
}
for (Region region : map.values()) {
locations.add(new LocationImpl(LocationScope.REGION, region.toString(), region.toString(),
null, true));
}
return Maps.uniqueIndex(locations, new Function<Location, String>() {
@Override
public String apply(Location from) {
return from.getId();
}
});
}
@Provides
@Singleton
Location getDefaultLocation(@EC2 Region region, Map<String, ? extends Location> map) {
return map.get(region.toString());
} }
private static class LogHolder { private static class LogHolder {
@ -101,13 +164,24 @@ public class EC2ComputeServiceContextModule extends EC2ContextModule {
@Provides @Provides
@Singleton @Singleton
protected Set<? extends Image> provideImages(final EC2Client sync, Map<Region, URI> regionMap, @Named(PROPERTY_EC2_AMI_OWNERS)
LogHolder holder) throws InterruptedException, ExecutionException, TimeoutException { String[] amiOwners(@Named(PROPERTY_EC2_AMI_OWNERS) String amiOwners) {
return Iterables.toArray(Splitter.on('.').split(amiOwners), String.class);
}
@Provides
@Singleton
protected Map<String, ? extends Image> provideImages(final EC2Client sync,
Map<Region, URI> regionMap, LogHolder holder,
Function<ComputeMetadata, String> indexer,
@Named(PROPERTY_EC2_AMI_OWNERS) String[] amiOwners) throws InterruptedException,
ExecutionException, TimeoutException {
final Set<Image> images = Sets.newHashSet(); final Set<Image> images = Sets.newHashSet();
holder.logger.debug(">> providing images"); holder.logger.debug(">> providing images");
for (final Region region : regionMap.keySet()) { for (final Region region : regionMap.keySet()) {
for (final org.jclouds.aws.ec2.domain.Image from : sync.getAMIServices() for (final org.jclouds.aws.ec2.domain.Image from : sync.getAMIServices()
.describeImagesInRegion(region, ownedBy("063491364108"))) { .describeImagesInRegion(region, ownedBy(amiOwners))) {
OsFamily os = null; OsFamily os = null;
String osDescription = from.getImageLocation(); String osDescription = from.getImageLocation();
String version = ""; String version = "";
@ -122,10 +196,22 @@ public class EC2ComputeServiceContextModule extends EC2ContextModule {
holder.logger.debug("<< didn't match os(%s)", matcher.group(1)); holder.logger.debug("<< didn't match os(%s)", matcher.group(1));
} }
} }
images.add(new EC2Image(from, os, osDescription, version)); images
.add(new ImageImpl(
from.getId(),
from.getName(),
region.toString(),
null,
ImmutableMap.<String, String> of(),
from.getDescription(),
version,
os,
osDescription,
from.getArchitecture() == org.jclouds.aws.ec2.domain.Image.Architecture.I386 ? Architecture.X86_32
: Architecture.X86_64));
} }
} }
holder.logger.debug("<< images(%d)", images.size()); holder.logger.debug("<< images(%d)", images.size());
return images; return Maps.uniqueIndex(images, indexer);
} }
} }

View File

@ -1,139 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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.domain;
import org.jclouds.compute.domain.Architecture;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.OsFamily;
/**
*
* @author Adrian Cole
*/
public class EC2Image implements Image {
private final org.jclouds.aws.ec2.domain.Image image;
private final OsFamily os;
private final String osDescription;
private final String version;
public EC2Image(org.jclouds.aws.ec2.domain.Image image, OsFamily os, String osDescription,
String version) {
this.image = image;
this.os = os;
this.osDescription = osDescription;
this.version = version;
}
@Override
public Architecture getArchitecture() {
return getImage().getArchitecture() == org.jclouds.aws.ec2.domain.Image.Architecture.I386 ? Architecture.X86_32
: Architecture.X86_64;
}
@Override
public String getDescription() {
return getImage().getDescription();
}
@Override
public String getId() {
return getImage().getId();
}
@Override
public String getLocation() {
return getImage().getRegion().toString();
}
@Override
public OsFamily getOsFamily() {
return os;
}
@Override
public String getOsDescription() {
return osDescription;
}
@Override
public String getVersion() {
return version;
}
public org.jclouds.aws.ec2.domain.Image getImage() {
return image;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((image == null) ? 0 : image.hashCode());
result = prime * result + ((os == null) ? 0 : os.hashCode());
result = prime * result + ((osDescription == null) ? 0 : osDescription.hashCode());
result = prime * result + ((version == null) ? 0 : version.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
EC2Image other = (EC2Image) obj;
if (image == null) {
if (other.image != null)
return false;
} else if (!image.equals(other.image))
return false;
if (os == null) {
if (other.os != null)
return false;
} else if (!os.equals(other.os))
return false;
if (osDescription == null) {
if (other.osDescription != null)
return false;
} else if (!osDescription.equals(other.osDescription))
return false;
if (version == null) {
if (other.version != null)
return false;
} else if (!version.equals(other.version))
return false;
return true;
}
@Override
public String toString() {
return "[id=" + getId() + ", version=" + version + ", location=" + getLocation()
+ ", architecture=" + getArchitecture() + ", operatingSystem="
+ getOsFamily() + ", operatingSystemVersion=" + getOsDescription()
+ ", description=" + getDescription() + "]";
}
}

View File

@ -27,6 +27,7 @@ import org.jclouds.aws.ec2.domain.InstanceType;
import org.jclouds.compute.domain.Architecture; import org.jclouds.compute.domain.Architecture;
import org.jclouds.compute.domain.internal.SizeImpl; import org.jclouds.compute.domain.internal.SizeImpl;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
/** /**
@ -34,11 +35,14 @@ import com.google.common.collect.ImmutableSet;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class EC2Size extends SizeImpl { public class EC2Size extends SizeImpl {
/** The serialVersionUID */
private static final long serialVersionUID = 8605688733788974797L;
private final InstanceType instanceType; private final InstanceType instanceType;
EC2Size(InstanceType instanceType, Integer cores, Integer ram, Integer disk, EC2Size(InstanceType instanceType, Integer cores, Integer ram, Integer disk,
Iterable<Architecture> supportedArchitectures) { Iterable<Architecture> supportedArchitectures) {
super(instanceType.toString(), cores, ram, disk, supportedArchitectures); super(instanceType.toString(), instanceType.toString(), null, null, ImmutableMap
.<String, String> of(),cores, ram, disk, supportedArchitectures);
this.instanceType = instanceType; this.instanceType = instanceType;
} }

View File

@ -0,0 +1,39 @@
package org.jclouds.aws.ec2.compute.domain;
import org.jclouds.aws.ec2.domain.KeyPair;
import org.jclouds.domain.Credentials;
public class KeyPairCredentials extends Credentials {
private final KeyPair keyPair;
public KeyPairCredentials(String account, KeyPair keyPair) {
super(account, keyPair.getKeyMaterial());
this.keyPair = keyPair;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((keyPair == null) ? 0 : keyPair.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
KeyPairCredentials other = (KeyPairCredentials) obj;
if (keyPair == null) {
if (other.keyPair != null)
return false;
} else if (!keyPair.equals(other.keyPair))
return false;
return true;
}
}

View File

@ -0,0 +1,20 @@
package org.jclouds.aws.ec2.compute.domain;
import org.jclouds.aws.domain.Region;
public class PortsRegionTag extends RegionTag {
private final int[] ports;
public PortsRegionTag(Region region, String tag, int[] ports) {
super(region, tag);
this.ports = ports;
}
// intentionally not overriding equals or hash-code so that we can search only by region/tag in a
// map
public int[] getPorts() {
return ports;
}
}

View File

@ -0,0 +1,54 @@
package org.jclouds.aws.ec2.compute.domain;
import org.jclouds.aws.domain.Region;
public class RegionTag {
protected final Region region;
protected final String tag;
public RegionTag(Region region, String tag) {
this.region = region;
this.tag = tag;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((region == null) ? 0 : region.hashCode());
result = prime * result + ((tag == null) ? 0 : tag.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
RegionTag other = (RegionTag) obj;
if (region == null) {
if (other.region != null)
return false;
} else if (!region.equals(other.region))
return false;
if (tag == null) {
if (other.tag != null)
return false;
} else if (!tag.equals(other.tag))
return false;
return true;
}
public Region getRegion() {
return region;
}
public String getTag() {
return tag;
}
}

View File

@ -0,0 +1,54 @@
package org.jclouds.aws.ec2.compute.functions;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.aws.AWSResponseException;
import org.jclouds.aws.domain.Region;
import org.jclouds.aws.ec2.EC2Client;
import org.jclouds.aws.ec2.compute.domain.KeyPairCredentials;
import org.jclouds.aws.ec2.compute.domain.RegionTag;
import org.jclouds.aws.ec2.domain.KeyPair;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
@Singleton
public class CreateKeyPairIfNeeded implements Function<RegionTag, KeyPairCredentials> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
protected final EC2Client ec2Client;
@Inject
public CreateKeyPairIfNeeded(EC2Client ec2Client) {
this.ec2Client = ec2Client;
}
@Override
public KeyPairCredentials apply(RegionTag from) {
return new KeyPairCredentials("root", createKeyPairInRegion(from.getRegion(), from.getTag()));
}
private KeyPair createKeyPairInRegion(Region region, String name) {
logger.debug(">> creating keyPair region(%s) name(%s)", region, name);
KeyPair keyPair;
try {
keyPair = ec2Client.getKeyPairServices().createKeyPairInRegion(region, name);
logger.debug("<< created keyPair(%s)", keyPair.getKeyName());
} catch (AWSResponseException e) {
if (e.getError().getCode().equals("InvalidKeyPair.Duplicate")) {
keyPair = Iterables.getLast(ec2Client.getKeyPairServices().describeKeyPairsInRegion(
region, name));
logger.debug("<< reused keyPair(%s)", keyPair.getKeyName());
} else {
throw e;
}
}
return keyPair;
}
}

View File

@ -0,0 +1,57 @@
package org.jclouds.aws.ec2.compute.functions;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.aws.AWSResponseException;
import org.jclouds.aws.domain.Region;
import org.jclouds.aws.ec2.EC2Client;
import org.jclouds.aws.ec2.compute.domain.PortsRegionTag;
import org.jclouds.aws.ec2.domain.IpProtocol;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
@Singleton
public class CreateSecurityGroupIfNeeded implements Function<PortsRegionTag, String> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
protected final EC2Client ec2Client;
@Inject
public CreateSecurityGroupIfNeeded(EC2Client ec2Client) {
this.ec2Client = ec2Client;
}
@Override
public String apply(PortsRegionTag from) {
createSecurityGroupInRegion(from.getRegion(), from.getTag(), from.getPorts());
return from.getTag();
}
private void createSecurityGroupInRegion(Region region, String name, int... ports) {
logger.debug(">> creating securityGroup region(%s) name(%s)", region, name);
try {
ec2Client.getSecurityGroupServices().createSecurityGroupInRegion(region, name, name);
logger.debug("<< created securityGroup(%s)", name);
for (int port : ports) {
logger.debug(">> authorizing securityGroup region(%s) name(%s) port(%s)", region, name,
port);
ec2Client.getSecurityGroupServices().authorizeSecurityGroupIngressInRegion(region,
name, IpProtocol.TCP, port, port, "0.0.0.0/0");
logger.debug("<< authorized securityGroup(%s)", name);
}
} catch (AWSResponseException e) {
if (e.getError().getCode().equals("InvalidGroup.Duplicate")) {
logger.debug("<< reused securityGroup(%s)", name);
} else {
throw e;
}
}
}
}

View File

@ -0,0 +1,63 @@
package org.jclouds.aws.ec2.compute.functions;
import java.net.InetAddress;
import java.net.URI;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.aws.ec2.compute.domain.KeyPairCredentials;
import org.jclouds.aws.ec2.compute.domain.RegionTag;
import org.jclouds.aws.ec2.domain.InstanceState;
import org.jclouds.aws.ec2.domain.RunningInstance;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.internal.NodeMetadataImpl;
import org.jclouds.domain.Credentials;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@Singleton
public class RunningInstanceToNodeMetadata implements Function<RunningInstance, NodeMetadata> {
private static final Map<InstanceState, NodeState> instanceToNodeState = ImmutableMap
.<InstanceState, NodeState> builder().put(InstanceState.PENDING, NodeState.PENDING)
.put(InstanceState.RUNNING, NodeState.RUNNING).put(InstanceState.SHUTTING_DOWN,
NodeState.PENDING).put(InstanceState.TERMINATED, NodeState.TERMINATED).build();
private final Map<RegionTag, KeyPairCredentials> credentialsMap;
@Inject
public RunningInstanceToNodeMetadata(Map<RegionTag, KeyPairCredentials> credentialsMap) {
this.credentialsMap = credentialsMap;
}
@Override
public NodeMetadata apply(RunningInstance from) {
String id = from.getId();
String name = null; // user doesn't determine a node name;
URI uri = null; // no uri to get rest access to host info
Map<String, String> userMetadata = ImmutableMap.<String, String> of();
String tag = from.getKeyName();
NodeState state = instanceToNodeState.get(from.getInstanceState());
Set<InetAddress> publicAddresses = nullSafeSet(from.getIpAddress());
Set<InetAddress> privateAddresses = nullSafeSet(from.getPrivateIpAddress());
Credentials credentials = credentialsMap.containsKey(new RegionTag(from.getRegion(), tag)) ? credentialsMap
.get(new RegionTag(from.getRegion(), tag))
: null;
String locationId = from.getAvailabilityZone().toString();
Map<String, String> extra = ImmutableMap.<String, String> of();
return new NodeMetadataImpl(id, name, locationId, uri, userMetadata, tag, state,
publicAddresses, privateAddresses, extra, credentials);
}
Set<InetAddress> nullSafeSet(InetAddress in) {
if (in == null) {
return ImmutableSet.<InetAddress> of();
}
return ImmutableSet.<InetAddress> of(in);
}
}

View File

@ -32,6 +32,7 @@ import org.jclouds.aws.ec2.domain.AvailabilityZone;
import org.jclouds.aws.ec2.domain.AvailabilityZoneInfo; import org.jclouds.aws.ec2.domain.AvailabilityZoneInfo;
import org.jclouds.aws.ec2.domain.RunningInstance; import org.jclouds.aws.ec2.domain.RunningInstance;
import org.jclouds.aws.ec2.predicates.InstanceStateRunning; import org.jclouds.aws.ec2.predicates.InstanceStateRunning;
import org.jclouds.aws.ec2.predicates.InstanceStateTerminated;
import org.jclouds.aws.ec2.reference.EC2Constants; import org.jclouds.aws.ec2.reference.EC2Constants;
import org.jclouds.aws.ec2.services.AMIAsyncClient; import org.jclouds.aws.ec2.services.AMIAsyncClient;
import org.jclouds.aws.ec2.services.AMIClient; import org.jclouds.aws.ec2.services.AMIClient;
@ -91,7 +92,8 @@ public class EC2RestClientModule extends AbstractModule {
@Provides @Provides
@Singleton @Singleton
@Named("TERMINATED") @Named("TERMINATED")
protected Predicate<RunningInstance> instanceStateTerminated(InstanceStateRunning stateTerminated) { protected Predicate<RunningInstance> instanceStateTerminated(
InstanceStateTerminated stateTerminated) {
return new RetryablePredicate<RunningInstance>(stateTerminated, 600, 50, return new RetryablePredicate<RunningInstance>(stateTerminated, 600, 50,
TimeUnit.MILLISECONDS); TimeUnit.MILLISECONDS);
} }

View File

@ -19,6 +19,7 @@
package org.jclouds.aws.ec2.reference; package org.jclouds.aws.ec2.reference;
import org.jclouds.aws.reference.AWSConstants; import org.jclouds.aws.reference.AWSConstants;
import org.jclouds.compute.ComputeService;
/** /**
* Configuration properties and constants used in EC2 connections. * Configuration properties and constants used in EC2 connections.
@ -27,5 +28,10 @@ import org.jclouds.aws.reference.AWSConstants;
*/ */
public interface EC2Constants extends AWSConstants { public interface EC2Constants extends AWSConstants {
public static final String PROPERTY_EC2_ENDPOINT = "jclouds.ec2.endpoint"; public static final String PROPERTY_EC2_ENDPOINT = "jclouds.ec2.endpoint";
/**
* Listing the universe of amis is extremely expensive. set this to a comma separated value of
* the ami owners you wish to use in {@link ComputeService}
*/
public static final String PROPERTY_EC2_AMI_OWNERS = "jclouds.ec2.ami-owners";
} }

View File

@ -65,6 +65,7 @@ public interface KeyPairAsyncClient {
@EndpointParam(parser = RegionToEndpoint.class) Region region, @EndpointParam(parser = RegionToEndpoint.class) Region region,
@FormParam("KeyName") String keyName); @FormParam("KeyName") String keyName);
// map resourcenotfoundexception to empty set
/** /**
* @see KeyPairClient#describeKeyPairsInRegion * @see KeyPairClient#describeKeyPairsInRegion
*/ */

View File

@ -34,6 +34,7 @@ import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException; import org.jclouds.http.HttpResponseException;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.util.Utils; import org.jclouds.util.Utils;
import com.google.common.io.Closeables; import com.google.common.io.Closeables;
@ -78,6 +79,8 @@ public class ParseAWSErrorFromXmlContent implements HttpErrorHandler {
if (content.indexOf('<') >= 0) { if (content.indexOf('<') >= 0) {
AWSError error = utils.parseAWSErrorFromContent(command, response, content); AWSError error = utils.parseAWSErrorFromContent(command, response, content);
exception = new AWSResponseException(command, response, error); exception = new AWSResponseException(command, response, error);
if (error.getCode().indexOf("NotFound") >= 0)
exception = new ResourceNotFoundException(exception);
} else { } else {
exception = new HttpResponseException(command, response, content); exception = new HttpResponseException(command, response, content);
} }

View File

@ -113,11 +113,9 @@ public interface BlobStore {
* fully qualified name relative to the container. * fully qualified name relative to the container.
* @param options * @param options
* byte range or condition options * byte range or condition options
* @return the blob you intended to receive. * @return the blob you intended to receive or null, if it doesn't exist.
* @throws ContainerNotFoundException * @throws ContainerNotFoundException
* if the container doesn't exist * if the container doesn't exist
* @throws KeyNotFoundException
* if the container doesn't exist
*/ */
Blob getBlob(String container, String name); Blob getBlob(String container, String name);

View File

@ -66,7 +66,7 @@ public interface StorageMetadata extends ResourceMetadata<StorageType> {
* *
*/ */
@Override @Override
String getLocation(); String getLocationId();
/** /**
* URI used to access this resource * URI used to access this resource

View File

@ -41,9 +41,9 @@ public class BlobMetadataImpl extends StorageMetadataImpl implements Serializabl
private final String contentType; private final String contentType;
private final byte[] contentMD5; private final byte[] contentMD5;
public BlobMetadataImpl(String id, String name, @Nullable String location, URI uri, String eTag, public BlobMetadataImpl(String id, String name, @Nullable String location, URI uri,
Long size, Date lastModified, Map<String, String> userMetadata, String contentType, String eTag, Long size, Date lastModified, Map<String, String> userMetadata,
byte[] contentMD5) { String contentType, byte[] contentMD5) {
super(StorageType.BLOB, id, name, location, uri, eTag, size, lastModified, userMetadata); super(StorageType.BLOB, id, name, location, uri, eTag, size, lastModified, userMetadata);
this.contentType = contentType; this.contentType = contentType;
this.contentMD5 = contentMD5; this.contentMD5 = contentMD5;

View File

@ -38,7 +38,7 @@ public class ResourceMetadataToRelativePathResourceMetadata implements
name = name.substring(0, name.length() - suffix.length()); name = name.substring(0, name.length() - suffix.length());
} }
return new StorageMetadataImpl(StorageType.RELATIVE_PATH, md.getId(), name, md return new StorageMetadataImpl(StorageType.RELATIVE_PATH, md.getId(), name, md
.getLocation(), md.getUri(), md.getETag(), md.getSize(), md.getLastModified(), md .getLocationId(), md.getUri(), md.getETag(), md.getSize(), md.getLastModified(), md
.getUserMetadata()); .getUserMetadata());
} }

View File

@ -65,7 +65,7 @@ public class BlobStoreUtils {
blob.getMetadata().setETag(blobMeta.getETag()); blob.getMetadata().setETag(blobMeta.getETag());
blob.getMetadata().setId(blobMeta.getId()); blob.getMetadata().setId(blobMeta.getId());
blob.getMetadata().setLastModified(blobMeta.getLastModified()); blob.getMetadata().setLastModified(blobMeta.getLastModified());
blob.getMetadata().setLocation(blobMeta.getLocation()); blob.getMetadata().setLocationId(blobMeta.getLocationId());
blob.getMetadata().setUri(blobMeta.getUri()); blob.getMetadata().setUri(blobMeta.getUri());
blob.getMetadata().setUserMetadata(blobMeta.getUserMetadata()); blob.getMetadata().setUserMetadata(blobMeta.getUserMetadata());
return blob; return blob;

View File

@ -18,16 +18,16 @@
*/ */
package org.jclouds.compute; package org.jclouds.compute;
import java.util.Set; import java.util.Map;
import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.CreateNodeResponse;
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.NodeSet;
import org.jclouds.compute.domain.Size; import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.options.RunNodeOptions; import org.jclouds.domain.Location;
/** /**
* Provides portable access to launching compute instances. * Provides portable access to launching compute instances.
@ -42,36 +42,62 @@ public interface ComputeService {
TemplateBuilder templateBuilder(); TemplateBuilder templateBuilder();
/** /**
* List all sizes available to the current user * all sizes available to the current user by id
*/ */
Set<? extends Size> listSizes(); Map<String, ? extends Size> getSizes();
/** /**
* List all images available to the current user * all images available to the current user by id
*/ */
Set<? extends Image> listImages(); Map<String, ? extends Image> getImages();
/** /**
* List all nodes available to the current user * all nodes available to the current user by id. If possible, the returned set will include
* {@link NodeMetadata} objects.
*/ */
Set<? extends ComputeMetadata> listNodes(); Map<String, ? extends ComputeMetadata> getNodes();
/** /**
* Create a new node given the name, and template * all nodes available to the current user by id
*/
Map<String, ? extends Location> getLocations();
/**
* create and run nodes in the specified tagset. If resources needed are currently available for
* this tag, they will be reused. Otherwise, they will be created. Inbound port 22 will always be
* opened up.
*
* @param tag
* - common identifier to group nodes by, cannot contain hyphens
* @param maxNodes
* - how many to fire up.
* @param template
* - how to configure the nodes
* *
*/ */
CreateNodeResponse runNode(String name, Template template); NodeSet runNodes(String tag, int maxNodes, Template template);
CreateNodeResponse runNode(String name, Template template, RunNodeOptions options);
/** /**
* destroy the node. * destroy the node. If it is the only node in a tag set, the dependent resources will also be
* destroyed.
*/ */
void destroyNode(ComputeMetadata node); void destroyNode(ComputeMetadata node);
/**
* destroy the nodes identified by this tag.
*/
void destroyNodes(String tag);
/** /**
* Find a node by its id * Find a node by its id
*/ */
NodeMetadata getNodeMetadata(ComputeMetadata node); NodeMetadata getNodeMetadata(ComputeMetadata node);
/**
* get all nodes matching the tag.
*
* @param tag
*/
NodeSet getNodes(String tag);
} }

View File

@ -50,11 +50,4 @@ public interface ComputeMetadata extends ResourceMetadata<ComputeType> {
@Override @Override
public String getName(); public String getName();
/**
* location where the node exists..
*
*/
@Override
public String getLocation();
} }

View File

@ -23,23 +23,22 @@
*/ */
package org.jclouds.compute.domain; package org.jclouds.compute.domain;
import org.jclouds.compute.domain.internal.ImageImpl;
import com.google.inject.ImplementedBy;
/** /**
* Running Operating system * Running Operating system
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public interface Image { @ImplementedBy(ImageImpl.class)
public interface Image extends ComputeMetadata {
/** /**
* Unique ID provided by the provider (ami-abcd1234, etc) * Version of the image
*
*/ */
String getId(); String getVersion();
/**
* Description of the image
*/
String getDescription();
/** /**
* Operating System * Operating System
@ -51,16 +50,6 @@ public interface Image {
*/ */
String getOsDescription(); String getOsDescription();
/**
* Version of the image
*/
String getVersion();
/**
* Geographic location of the image.
*/
String getLocation();
/** /**
* Operating System * Operating System
*/ */

View File

@ -20,18 +20,43 @@ package org.jclouds.compute.domain;
import java.net.InetAddress; import java.net.InetAddress;
import java.util.Map; import java.util.Map;
import java.util.SortedSet; import java.util.Set;
import org.jclouds.domain.Credentials;
/** /**
* @author Adrian Cole * @author Adrian Cole
* @author Ivan Meredith * @author Ivan Meredith
*/ */
public interface NodeMetadata extends ComputeMetadata { public interface NodeMetadata extends ComputeMetadata {
/**
* Tag used for all resources that belong to the same logical group. run, destroy commands are
* scoped to tag.
*
*/
String getTag();
/**
* Current State of the node
*/
NodeState getState(); NodeState getState();
SortedSet<InetAddress> getPublicAddresses(); /**
* All public IP addresses, potentially including shared ips.
*/
Set<InetAddress> getPublicAddresses();
SortedSet<InetAddress> getPrivateAddresses(); /**
* All private IP addresses.
*/
Set<InetAddress> getPrivateAddresses();
/**
* If possible, these are returned upon all detail requests. However, it is often the case that
* credentials are only available at "run" time.
*/
Credentials getCredentials();
/** /**
* Other variables present that the provider supports * Other variables present that the provider supports

View File

@ -18,14 +18,11 @@
*/ */
package org.jclouds.compute.domain; package org.jclouds.compute.domain;
import org.jclouds.domain.Credentials; import java.util.Set;
/** /**
* @author Adrian Cole * @author Adrian Cole
* @author Ivan Meredith
*/ */
public interface CreateNodeResponse extends NodeMetadata { public interface NodeSet extends Set<NodeMetadata> {
Credentials getCredentials();
} }

View File

@ -23,6 +23,8 @@
*/ */
package org.jclouds.compute.domain; package org.jclouds.compute.domain;
import java.util.Set;
import org.jclouds.compute.domain.internal.SizeImpl; import org.jclouds.compute.domain.internal.SizeImpl;
import com.google.inject.ImplementedBy; import com.google.inject.ImplementedBy;
@ -33,12 +35,7 @@ import com.google.inject.ImplementedBy;
* @author Adrian Cole * @author Adrian Cole
*/ */
@ImplementedBy(SizeImpl.class) @ImplementedBy(SizeImpl.class)
public interface Size extends Comparable<Size> { public interface Size extends ComputeMetadata {
/**
* unique identifier of this configuration.
*/
String getId();
/** /**
* Amount of virtual or physical cores provided * Amount of virtual or physical cores provided
@ -58,5 +55,5 @@ public interface Size extends Comparable<Size> {
/** /**
* Determines platforms this can support * Determines platforms this can support
*/ */
boolean supportsArchitecture(Architecture architecture); Set<Architecture> getSupportedArchitectures();
} }

View File

@ -18,6 +18,9 @@
*/ */
package org.jclouds.compute.domain; package org.jclouds.compute.domain;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.domain.Location;
/** /**
* Configured operating system used to start nodes. * Configured operating system used to start nodes.
* *
@ -35,4 +38,13 @@ public interface Template extends Cloneable {
*/ */
Size getSize(); Size getSize();
/**
* Location of the nodes.
*/
Location getLocation();
/**
* options for launching this template, like run scripts or inbound ports
*/
TemplateOptions getOptions();
} }

View File

@ -24,6 +24,7 @@
package org.jclouds.compute.domain; package org.jclouds.compute.domain;
import org.jclouds.compute.internal.TemplateBuilderImpl; import org.jclouds.compute.internal.TemplateBuilderImpl;
import org.jclouds.compute.options.TemplateOptions;
import com.google.inject.ImplementedBy; import com.google.inject.ImplementedBy;
@ -72,7 +73,7 @@ public interface TemplateBuilder {
/** /**
* Configure this template to start in a specific location * Configure this template to start in a specific location
*/ */
TemplateBuilder location(String location); TemplateBuilder locationId(String locationId);
/** /**
* Configure this template to require a specific architecture * Configure this template to require a specific architecture
@ -121,4 +122,9 @@ public interface TemplateBuilder {
* Generate an immutable template from the current builder. * Generate an immutable template from the current builder.
*/ */
Template build(); Template build();
/**
* options such as inbound ports and run scripts.
*/
TemplateBuilder options(TemplateOptions options);
} }

View File

@ -35,9 +35,9 @@ public class ComputeMetadataImpl extends ResourceMetadataImpl<ComputeType> imple
/** The serialVersionUID */ /** The serialVersionUID */
private static final long serialVersionUID = 7374704415964898694L; private static final long serialVersionUID = 7374704415964898694L;
public ComputeMetadataImpl(ComputeType type, String id, String name, String location, URI uri, public ComputeMetadataImpl(ComputeType type, String id, String name, String locationId, URI uri,
Map<String, String> userMetadata) { Map<String, String> userMetadata) {
super(type, id, name, location, uri, userMetadata); super(type, id, name, locationId, uri, userMetadata);
} }
} }

View File

@ -1,77 +0,0 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package org.jclouds.compute.domain.internal;
import java.net.InetAddress;
import java.net.URI;
import java.util.Map;
import org.jclouds.compute.domain.CreateNodeResponse;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.domain.Credentials;
/**
* @author Adrian Cole
* @author Ivan Meredith
*/
public class CreateNodeResponseImpl extends NodeMetadataImpl implements CreateNodeResponse {
/** The serialVersionUID */
private static final long serialVersionUID = 3414239861247046054L;
private final Credentials credentials;
public CreateNodeResponseImpl(String id, String name, String location, URI uri,
Map<String, String> userMetadata, NodeState state,
Iterable<InetAddress> publicAddresses, Iterable<InetAddress> privateAddresses,
Credentials credentials, Map<String, String> extra) {
super(id, name, location, uri, userMetadata, state, publicAddresses, privateAddresses, extra);
this.credentials = credentials;
}
public Credentials getCredentials() {
return credentials;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((credentials == null) ? 0 : credentials.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
CreateNodeResponseImpl other = (CreateNodeResponseImpl) obj;
if (credentials == null) {
if (other.credentials != null)
return false;
} else if (!credentials.equals(other.credentials))
return false;
return true;
}
}

View File

@ -23,125 +23,39 @@
*/ */
package org.jclouds.compute.domain.internal; package org.jclouds.compute.domain.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI;
import java.util.Map;
import javax.annotation.Nullable;
import org.jclouds.compute.domain.Architecture; import org.jclouds.compute.domain.Architecture;
import org.jclouds.compute.domain.ComputeType;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.OsFamily;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
public class ImageImpl implements Image { public class ImageImpl extends ComputeMetadataImpl implements Image {
/** The serialVersionUID */
private static final long serialVersionUID = 7856744554191025307L;
private final String id;
private final String description;
private final String version; private final String version;
private final OsFamily operatingSystem; private final OsFamily osFamily;
private final String operatingSystemDescription; private final String osDescription;
private final String location;
private final Architecture architecture; private final Architecture architecture;
/** public ImageImpl(String id, String name, String locationId, URI uri,
* {@inheritDoc} Map<String, String> userMetadata, String description, String version,
*/ @Nullable OsFamily osFamily, String osDescription, Architecture architecture) {
@Override super(ComputeType.IMAGE, id, name, locationId, uri, userMetadata);
public int hashCode() { this.version = checkNotNull(version, "version");
final int prime = 31; this.osFamily = osFamily;
int result = 1; this.osDescription = checkNotNull(osDescription, "osDescription");
result = prime * result + ((architecture == null) ? 0 : architecture.hashCode()); this.architecture = checkNotNull(architecture, "architecture");
result = prime * result + ((description == null) ? 0 : description.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((location == null) ? 0 : location.hashCode());
result = prime * result + ((operatingSystem == null) ? 0 : operatingSystem.hashCode());
result = prime * result + ((version == null) ? 0 : version.hashCode());
return result;
}
public ImageImpl(String id, String description, String version, OsFamily operatingSystem,
String operatingSystemDescription, String location, Architecture architecture) {
this.id = id;
this.description = description;
this.version = version;
this.operatingSystem = operatingSystem;
this.operatingSystemDescription = operatingSystemDescription;
this.location = location;
this.architecture = architecture;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ImageImpl other = (ImageImpl) obj;
if (architecture == null) {
if (other.architecture != null)
return false;
} else if (!architecture.equals(other.architecture))
return false;
if (description == null) {
if (other.description != null)
return false;
} else if (!description.equals(other.description))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (location == null) {
if (other.location != null)
return false;
} else if (!location.equals(other.location))
return false;
if (operatingSystem == null) {
if (other.operatingSystem != null)
return false;
} else if (!operatingSystem.equals(other.operatingSystem))
return false;
if (version == null) {
if (other.version != null)
return false;
} else if (!version.equals(other.version))
return false;
return true;
}
@Override
public String toString() {
return "[id=" + id + ", version=" + version + ", location=" + location + ", architecture="
+ architecture + ", operatingSystem=" + operatingSystem
+ ", operatingSystemVersion=" + operatingSystemDescription + ", description="
+ description + "]";
}
/**
* {@inheritDoc}
*/
@Override
public String getId() {
return id;
}
/**
* {@inheritDoc}
*/
@Override
public String getDescription() {
return description;
}
/**
* {@inheritDoc}
*/
@Override
public OsFamily getOsFamily() {
return operatingSystem;
} }
/** /**
@ -156,8 +70,16 @@ public class ImageImpl implements Image {
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public String getLocation() { public OsFamily getOsFamily() {
return location; return osFamily;
}
/**
* {@inheritDoc}
*/
@Override
public String getOsDescription() {
return osDescription;
} }
/** /**
@ -168,12 +90,4 @@ public class ImageImpl implements Image {
return architecture; return architecture;
} }
/**
* {@inheritDoc}
*/
@Override
public String getOsDescription() {
return operatingSystemDescription;
}
} }

View File

@ -18,15 +18,19 @@
*/ */
package org.jclouds.compute.domain.internal; package org.jclouds.compute.domain.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.URI; import java.net.URI;
import java.util.Comparator;
import java.util.Map; import java.util.Map;
import java.util.SortedSet; import java.util.Set;
import javax.annotation.Nullable;
import org.jclouds.compute.domain.ComputeType; import org.jclouds.compute.domain.ComputeType;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeState; import org.jclouds.compute.domain.NodeState;
import org.jclouds.domain.Credentials;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
@ -40,47 +44,62 @@ public class NodeMetadataImpl extends ComputeMetadataImpl implements NodeMetadat
/** The serialVersionUID */ /** The serialVersionUID */
private static final long serialVersionUID = 7924307572338157887L; private static final long serialVersionUID = 7924307572338157887L;
public static final Comparator<InetAddress> ADDRESS_COMPARATOR = new Comparator<InetAddress>() {
@Override
public int compare(InetAddress o1, InetAddress o2) {
return (o1 == o2) ? 0 : o1.getHostAddress().compareTo(o2.getHostAddress());
}
};
private final NodeState state; private final NodeState state;
private final SortedSet<InetAddress> publicAddresses = Sets.newTreeSet(ADDRESS_COMPARATOR); private final Set<InetAddress> publicAddresses = Sets.newLinkedHashSet();
private final SortedSet<InetAddress> privateAddresses = Sets.newTreeSet(ADDRESS_COMPARATOR); private final Set<InetAddress> privateAddresses = Sets.newLinkedHashSet();
private final Map<String, String> extra = Maps.newLinkedHashMap(); private final Map<String, String> extra = Maps.newLinkedHashMap();
private final Credentials credentials;
private final String tag;
public NodeMetadataImpl(String id, String name, String location, URI uri, public NodeMetadataImpl(String id, String name, String locationId, URI uri,
Map<String, String> userMetadata, NodeState state, Map<String, String> userMetadata, String tag, NodeState state,
Iterable<InetAddress> publicAddresses, Iterable<InetAddress> privateAddresses, Iterable<InetAddress> publicAddresses, Iterable<InetAddress> privateAddresses,
Map<String, String> extra) { Map<String, String> extra, @Nullable Credentials credentials) {
super(ComputeType.NODE, id, name, location, uri, userMetadata); super(ComputeType.NODE, id, name, locationId, uri, userMetadata);
this.state = state; this.tag = checkNotNull(tag, "tag");
Iterables.addAll(this.publicAddresses, publicAddresses); this.state = checkNotNull(state, "state");
Iterables.addAll(this.privateAddresses, privateAddresses); Iterables.addAll(this.publicAddresses, checkNotNull(publicAddresses, "publicAddresses"));
this.extra.putAll(extra); Iterables.addAll(this.privateAddresses, checkNotNull(privateAddresses, "privateAddresses"));
this.extra.putAll(checkNotNull(extra, "extra"));
this.credentials = credentials;
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public SortedSet<InetAddress> getPublicAddresses() { @Override
public String getTag() {
return tag;
}
/**
* {@inheritDoc}
*/
@Override
public Credentials getCredentials() {
return credentials;
}
/**
* {@inheritDoc}
*/
@Override
public Set<InetAddress> getPublicAddresses() {
return publicAddresses; return publicAddresses;
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public SortedSet<InetAddress> getPrivateAddresses() { @Override
public Set<InetAddress> getPrivateAddresses() {
return privateAddresses; return privateAddresses;
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override
public NodeState getState() { public NodeState getState() {
return state; return state;
} }
@ -95,20 +114,22 @@ public class NodeMetadataImpl extends ComputeMetadataImpl implements NodeMetadat
@Override @Override
public String toString() { public String toString() {
return "[id=" + getId() + ", name=" + getName() + ", location=" + getLocation() + ", uri=" return "[id=" + getId() + ", tag=" + getTag() + ", name=" + getName() + ", location="
+ getUri() + ", userMetadata=" + getUserMetadata() + ", state=" + getState() + getLocationId() + ", uri=" + getUri() + ", userMetadata=" + getUserMetadata()
+ ", privateAddresses=" + privateAddresses + ", publicAddresses=" + publicAddresses + ", state=" + getState() + ", privateAddresses=" + privateAddresses
+ "]"; + ", publicAddresses=" + publicAddresses + "]";
} }
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = super.hashCode(); int result = super.hashCode();
result = prime * result + ((credentials == null) ? 0 : credentials.hashCode());
result = prime * result + ((extra == null) ? 0 : extra.hashCode()); result = prime * result + ((extra == null) ? 0 : extra.hashCode());
result = prime * result + ((privateAddresses == null) ? 0 : privateAddresses.hashCode()); result = prime * result + ((privateAddresses == null) ? 0 : privateAddresses.hashCode());
result = prime * result + ((publicAddresses == null) ? 0 : publicAddresses.hashCode()); result = prime * result + ((publicAddresses == null) ? 0 : publicAddresses.hashCode());
result = prime * result + ((state == null) ? 0 : state.hashCode()); result = prime * result + ((state == null) ? 0 : state.hashCode());
result = prime * result + ((tag == null) ? 0 : tag.hashCode());
return result; return result;
} }
@ -121,6 +142,11 @@ public class NodeMetadataImpl extends ComputeMetadataImpl implements NodeMetadat
if (getClass() != obj.getClass()) if (getClass() != obj.getClass())
return false; return false;
NodeMetadataImpl other = (NodeMetadataImpl) obj; NodeMetadataImpl other = (NodeMetadataImpl) obj;
if (credentials == null) {
if (other.credentials != null)
return false;
} else if (!credentials.equals(other.credentials))
return false;
if (extra == null) { if (extra == null) {
if (other.extra != null) if (other.extra != null)
return false; return false;
@ -141,6 +167,11 @@ public class NodeMetadataImpl extends ComputeMetadataImpl implements NodeMetadat
return false; return false;
} else if (!state.equals(other.state)) } else if (!state.equals(other.state))
return false; return false;
if (tag == null) {
if (other.tag != null)
return false;
} else if (!tag.equals(other.tag))
return false;
return true; return true;
} }

View File

@ -0,0 +1,40 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package org.jclouds.compute.domain.internal;
import java.util.HashSet;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeSet;
import com.google.common.collect.Iterables;
/**
* @author Adrian Cole
*/
public class NodeSetImpl extends HashSet<NodeMetadata> implements NodeSet {
/** The serialVersionUID */
private static final long serialVersionUID = 3414239861247046054L;
public NodeSetImpl(Iterable<NodeMetadata> nodes) {
Iterables.addAll(this, nodes);
}
}

View File

@ -18,10 +18,18 @@
*/ */
package org.jclouds.compute.domain.internal; package org.jclouds.compute.domain.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI;
import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.annotation.Nullable;
import org.jclouds.compute.domain.Architecture; import org.jclouds.compute.domain.Architecture;
import org.jclouds.compute.domain.ComputeType;
import org.jclouds.compute.domain.Size; import org.jclouds.compute.domain.Size;
import org.jclouds.domain.ResourceMetadata;
import com.google.common.collect.ComparisonChain; import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
@ -30,20 +38,24 @@ import com.google.common.collect.Sets;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
public class SizeImpl implements Size { public class SizeImpl extends ComputeMetadataImpl implements Size {
private String id; /** The serialVersionUID */
private static final long serialVersionUID = 8994255275911717567L;
private final int cores; private final int cores;
private final int ram; private final int ram;
private final int disk; private final int disk;
private final Set<Architecture> supportedArchitectures = Sets.newHashSet(); private final Set<Architecture> supportedArchitectures = Sets.newHashSet();
public SizeImpl(String id, int cores, int ram, int disk, public SizeImpl(String id, String name, @Nullable String location, URI uri,
Map<String, String> userMetadata, int cores, int ram, int disk,
Iterable<Architecture> supportedArchitectures) { Iterable<Architecture> supportedArchitectures) {
this.id = id; super(ComputeType.SIZE, id, name, location, uri, userMetadata);
this.cores = cores; this.cores = cores;
this.ram = ram; this.ram = ram;
this.disk = disk; this.disk = disk;
Iterables.addAll(this.supportedArchitectures, supportedArchitectures); Iterables.addAll(this.supportedArchitectures, checkNotNull(supportedArchitectures,
"supportedArchitectures"));
} }
/** /**
@ -70,55 +82,27 @@ public class SizeImpl implements Size {
return disk; return disk;
} }
/**
* {@inheritDoc}
*/
@Override @Override
public int hashCode() { public int compareTo(ResourceMetadata<ComputeType> that) {
final int prime = 31; if (that instanceof Size) {
int result = 1; Size thatSize = Size.class.cast(that);
result = prime * result + cores; return ComparisonChain.start().compare(this.getCores(), thatSize.getCores()).compare(
result = prime * result + disk; this.getRam(), thatSize.getRam()).compare(this.getDisk(), thatSize.getDisk())
result = prime * result + ((id == null) ? 0 : id.hashCode()); .result();
result = prime * result + ram; } else {
result = prime * result return super.compareTo(that);
+ ((supportedArchitectures == null) ? 0 : supportedArchitectures.hashCode()); }
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SizeImpl other = (SizeImpl) obj;
if (cores != other.cores)
return false;
if (disk != other.disk)
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (ram != other.ram)
return false;
if (supportedArchitectures == null) {
if (other.supportedArchitectures != null)
return false;
} else if (!supportedArchitectures.equals(other.supportedArchitectures))
return false;
return true;
}
public int compareTo(Size that) {
return ComparisonChain.start().compare(this.getCores(), that.getCores()).compare(
this.getRam(), that.getRam()).compare(this.getDisk(), that.getDisk()).result();
} }
/**
* {@inheritDoc}
*/
@Override @Override
public String toString() { public String toString() {
return "[id=" + id + ", cores=" + cores + ", ram=" + ram + ", disk=" + disk return "[id=" + getId() + ", cores=" + cores + ", ram=" + ram + ", disk=" + disk
+ ", supportedArchitectures=" + supportedArchitectures + "]"; + ", supportedArchitectures=" + supportedArchitectures + "]";
} }
@ -126,15 +110,7 @@ public class SizeImpl implements Size {
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public boolean supportsArchitecture(Architecture architecture) { public Set<Architecture> getSupportedArchitectures() {
return supportedArchitectures.contains(architecture); return supportedArchitectures;
}
/**
* {@inheritDoc}
*/
@Override
public String getId() {
return id;
} }
} }

View File

@ -23,9 +23,13 @@
*/ */
package org.jclouds.compute.domain.internal; package org.jclouds.compute.domain.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.Size; import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.domain.Location;
/** /**
* *
@ -35,10 +39,14 @@ public class TemplateImpl implements Template {
private final Image image; private final Image image;
private final Size size; private final Size size;
private final Location location;
private final TemplateOptions options;
protected TemplateImpl(Image image, Size size) { public TemplateImpl(Image image, Size size, Location location, TemplateOptions options) {
this.image = image; this.image = checkNotNull(image, "image");
this.size = size; this.size = checkNotNull(size, "size");
this.location = checkNotNull(location, "location");
this.options = checkNotNull(options, "options");
} }
/** /**
@ -57,11 +65,29 @@ public class TemplateImpl implements Template {
return size; return size;
} }
/**
* {@inheritDoc}
*/
@Override
public Location getLocation() {
return location;
}
/**
* {@inheritDoc}
*/
@Override
public TemplateOptions getOptions() {
return options;
}
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result + ((image == null) ? 0 : image.hashCode()); result = prime * result + ((image == null) ? 0 : image.hashCode());
result = prime * result + ((location == null) ? 0 : location.hashCode());
result = prime * result + ((options == null) ? 0 : options.hashCode());
result = prime * result + ((size == null) ? 0 : size.hashCode()); result = prime * result + ((size == null) ? 0 : size.hashCode());
return result; return result;
} }
@ -80,6 +106,16 @@ public class TemplateImpl implements Template {
return false; return false;
} else if (!image.equals(other.image)) } else if (!image.equals(other.image))
return false; return false;
if (location == null) {
if (other.location != null)
return false;
} else if (!location.equals(other.location))
return false;
if (options == null) {
if (other.options != null)
return false;
} else if (!options.equals(other.options))
return false;
if (size == null) { if (size == null) {
if (other.size != null) if (other.size != null)
return false; return false;
@ -98,6 +134,7 @@ public class TemplateImpl implements Template {
*/ */
@Override @Override
protected Object clone() throws CloneNotSupportedException { protected Object clone() throws CloneNotSupportedException {
return new TemplateImpl(image, size); return new TemplateImpl(image, size, location, options);
} }
} }

View File

@ -38,7 +38,7 @@ public class ComputeServiceContextImpl<X, Y> implements ComputeServiceContext {
public ComputeServiceContextImpl(ComputeService computeService, public ComputeServiceContextImpl(ComputeService computeService,
RestContext<X, Y> providerSpecificContext) { RestContext<X, Y> providerSpecificContext) {
this.computeService = checkNotNull(computeService, "computeService"); this.computeService = checkNotNull(computeService, "computeService");
this.providerSpecificContext = providerSpecificContext; this.providerSpecificContext = checkNotNull(providerSpecificContext, "providerSpecificContext");;
} }
public ComputeService getComputeService() { public ComputeService getComputeService() {

View File

@ -1,21 +1,26 @@
package org.jclouds.compute.internal; package org.jclouds.compute.internal;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Set;
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 org.jclouds.compute.domain.Architecture; import org.jclouds.compute.domain.Architecture;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.Size; import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.domain.internal.TemplateImpl; import org.jclouds.compute.domain.internal.TemplateImpl;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.ResourceLocation; import org.jclouds.domain.Location;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
@ -37,17 +42,17 @@ public class TemplateBuilderImpl implements TemplateBuilder {
@Named(ComputeServiceConstants.COMPUTE_LOGGER) @Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
private final Set<? extends Image> images; private final Map<String, ? extends Image> images;
private final Set<? extends Size> sizes; private final Map<String, ? extends Size> sizes;
private String location; private final Map<String, ? extends Location> locations;
private OsFamily os; private OsFamily os;
private Architecture arch; private Architecture arch;
private String locationId;
private String imageId; private String imageId;
private String sizeId; private String sizeId;
private String osDescription; private String osDescription;
private String imageVersion; private String imageVersion;
private String imageDescription; private String imageName;
private int minCores; private int minCores;
private int minRam; private int minRam;
@ -55,15 +60,29 @@ public class TemplateBuilderImpl implements TemplateBuilder {
private boolean biggest; private boolean biggest;
private boolean fastest; private boolean fastest;
private TemplateOptions options = TemplateOptions.NONE;
@Inject @Inject
public TemplateBuilderImpl(@ResourceLocation String location, Set<? extends Image> images, public TemplateBuilderImpl(Map<String, ? extends Location> locations,
Set<? extends Size> sizes) { Map<String, ? extends Image> images, Map<String, ? extends Size> sizes,
this.location = location; Location defaultLocation) {
this.locations = locations;
this.images = images; this.images = images;
this.sizes = sizes; this.sizes = sizes;
this.locationId = defaultLocation.getId();
} }
private final Predicate<Image> imageIdPredicate = new Predicate<Image>() { private final Predicate<ComputeMetadata> locationPredicate = new Predicate<ComputeMetadata>() {
@Override
public boolean apply(ComputeMetadata input) {
boolean returnVal = true;
if (locationId != null && input.getLocationId() != null)
returnVal = locationId.equals(input.getLocationId());
return returnVal;
}
};
private final Predicate<Image> idPredicate = new Predicate<Image>() {
@Override @Override
public boolean apply(Image input) { public boolean apply(Image input) {
boolean returnVal = true; boolean returnVal = true;
@ -78,16 +97,6 @@ public class TemplateBuilderImpl implements TemplateBuilder {
} }
}; };
private final Predicate<Image> locationPredicate = new Predicate<Image>() {
@Override
public boolean apply(Image input) {
boolean returnVal = true;
if (location != null)
returnVal = location.equals(input.getLocation());
return returnVal;
}
};
private final Predicate<Image> osPredicate = new Predicate<Image>() { private final Predicate<Image> osPredicate = new Predicate<Image>() {
@Override @Override
@ -136,15 +145,15 @@ public class TemplateBuilderImpl implements TemplateBuilder {
return returnVal; return returnVal;
} }
}; };
private final Predicate<Image> imageDescriptionPredicate = new Predicate<Image>() { private final Predicate<Image> imageNamePredicate = new Predicate<Image>() {
@Override @Override
public boolean apply(Image input) { public boolean apply(Image input) {
boolean returnVal = true; boolean returnVal = true;
if (imageDescription != null) { if (imageName != null) {
if (input.getDescription() == null) if (input.getName() == null)
returnVal = false; returnVal = false;
else else
returnVal = input.getDescription().matches(imageDescription); returnVal = input.getName().matches(imageName);
} }
return returnVal; return returnVal;
} }
@ -165,16 +174,16 @@ public class TemplateBuilderImpl implements TemplateBuilder {
} }
}; };
private final Predicate<Image> imagePredicate = Predicates.and(imageIdPredicate, private final Predicate<Image> imagePredicate = Predicates.and(idPredicate, locationPredicate,
locationPredicate, osPredicate, imageArchPredicate, osDescriptionPredicate, osPredicate, imageArchPredicate, osDescriptionPredicate, imageVersionPredicate,
imageVersionPredicate, imageDescriptionPredicate); imageNamePredicate);
private final Predicate<Size> sizeArchPredicate = new Predicate<Size>() { private final Predicate<Size> sizeArchPredicate = new Predicate<Size>() {
@Override @Override
public boolean apply(Size input) { public boolean apply(Size input) {
boolean returnVal = false; boolean returnVal = false;
if (arch != null) if (arch != null)
returnVal = input.supportsArchitecture(arch); returnVal = input.getSupportedArchitectures().contains(arch);
return returnVal; return returnVal;
} }
}; };
@ -192,8 +201,8 @@ public class TemplateBuilderImpl implements TemplateBuilder {
return input.getRam() >= TemplateBuilderImpl.this.minRam; return input.getRam() >= TemplateBuilderImpl.this.minRam;
} }
}; };
private final Predicate<Size> sizePredicate = Predicates.and(sizeIdPredicate, sizeArchPredicate, private final Predicate<Size> sizePredicate = Predicates.and(sizeIdPredicate, locationPredicate,
sizeCoresPredicate, sizeRamPredicate); sizeArchPredicate, sizeCoresPredicate, sizeRamPredicate);
static final Ordering<Size> DEFAULT_SIZE_ORDERING = new Ordering<Size>() { static final Ordering<Size> DEFAULT_SIZE_ORDERING = new Ordering<Size>() {
public int compare(Size left, Size right) { public int compare(Size left, Size right) {
@ -208,9 +217,8 @@ public class TemplateBuilderImpl implements TemplateBuilder {
}; };
static final Ordering<Image> DEFAULT_IMAGE_ORDERING = new Ordering<Image>() { static final Ordering<Image> DEFAULT_IMAGE_ORDERING = new Ordering<Image>() {
public int compare(Image left, Image right) { public int compare(Image left, Image right) {
return ComparisonChain.start().compare(left.getOsDescription(), return ComparisonChain.start().compare(left.getOsDescription(), right.getOsDescription())
right.getOsDescription()).compare(left.getVersion(), right.getVersion()) .compare(left.getVersion(), right.getVersion()).result();
.result();
} }
}; };
@ -229,6 +237,8 @@ public class TemplateBuilderImpl implements TemplateBuilder {
*/ */
@Override @Override
public TemplateBuilder fromSize(Size size) { public TemplateBuilder fromSize(Size size) {
if (size.getLocationId() != null)
this.locationId = size.getLocationId();
this.minCores = size.getCores(); this.minCores = size.getCores();
this.minRam = size.getRam(); this.minRam = size.getRam();
return this; return this;
@ -239,8 +249,8 @@ public class TemplateBuilderImpl implements TemplateBuilder {
*/ */
@Override @Override
public TemplateBuilder fromImage(Image image) { public TemplateBuilder fromImage(Image image) {
if (image.getLocation() != null) if (image.getLocationId() != null)
this.location = image.getLocation(); this.locationId = image.getLocationId();
if (image.getOsFamily() != null) if (image.getOsFamily() != null)
this.os = image.getOsFamily(); this.os = image.getOsFamily();
if (image.getOsDescription() != null) if (image.getOsDescription() != null)
@ -283,8 +293,10 @@ public class TemplateBuilderImpl implements TemplateBuilder {
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public TemplateBuilder location(String location) { public TemplateBuilder locationId(final String locationId) {
this.location = location; checkArgument(locations.get(checkNotNull(locationId, "locationId")) != null, "locationId "
+ locationId + " not configured in: " + locations.keySet());
this.locationId = locationId;
return this; return this;
} }
@ -314,7 +326,7 @@ public class TemplateBuilderImpl implements TemplateBuilder {
logger.debug(">> searching params(%s)", this); logger.debug(">> searching params(%s)", this);
Image image; Image image;
try { try {
image = DEFAULT_IMAGE_ORDERING.max(Iterables.filter(images, imagePredicate)); image = DEFAULT_IMAGE_ORDERING.max(Iterables.filter(images.values(), imagePredicate));
} catch (NoSuchElementException exception) { } catch (NoSuchElementException exception) {
throw new NoSuchElementException("image didn't match: " + toString() + "\n" + images); throw new NoSuchElementException("image didn't match: " + toString() + "\n" + images);
} }
@ -329,13 +341,14 @@ public class TemplateBuilderImpl implements TemplateBuilder {
sizeOrdering = Ordering.compound(ImmutableList.of(BY_CORES_ORDERING, sizeOrdering)); sizeOrdering = Ordering.compound(ImmutableList.of(BY_CORES_ORDERING, sizeOrdering));
Size size; Size size;
try { try {
size = sizeOrdering.max(Iterables.filter(sizes, sizePredicate)); size = sizeOrdering.max(Iterables.filter(sizes.values(), sizePredicate));
} catch (NoSuchElementException exception) { } catch (NoSuchElementException exception) {
throw new NoSuchElementException("size didn't match: " + toString() + "\n" + sizes); throw new NoSuchElementException("size didn't match: " + toString() + "\n" + sizes);
} }
logger.debug("<< matched size(%s)", size); logger.debug("<< matched size(%s)", size);
return new TemplateImpl(image, size) { Location location = locations.get(locationId);
}; logger.debug("<< matched location(%s)", location);
return new TemplateImpl(image, size, location, options);
} }
/** /**
@ -352,7 +365,7 @@ public class TemplateBuilderImpl implements TemplateBuilder {
*/ */
@Override @Override
public TemplateBuilder imageDescriptionMatches(String descriptionRegex) { public TemplateBuilder imageDescriptionMatches(String descriptionRegex) {
this.imageDescription = descriptionRegex; this.imageName = descriptionRegex;
return this; return this;
} }
@ -401,13 +414,22 @@ public class TemplateBuilderImpl implements TemplateBuilder {
return this; return this;
} }
/**
* {@inheritDoc}
*/
@Override
public TemplateBuilder options(TemplateOptions options) {
this.options = checkNotNull(options, "options");
return this;
}
@Override @Override
public String toString() { public String toString() {
return "[arch=" + arch + ", biggest=" + biggest + ", fastest=" + fastest return "[arch=" + arch + ", biggest=" + biggest + ", fastest=" + fastest
+ ", imageDescription=" + imageDescription + ", imageId=" + imageId + ", imageDescription=" + imageName + ", imageId=" + imageId + ", imageVersion="
+ ", imageVersion=" + imageVersion + ", location=" + location + ", minCores=" + imageVersion + ", location=" + locationId + ", minCores=" + minCores + ", minRam="
+ minCores + ", minRam=" + minRam + ", os=" + os + ", osDescription=" + osDescription + minRam + ", os=" + os + ", osDescription=" + osDescription + ", sizeId=" + sizeId
+ ", sizeId=" + sizeId + "]"; + "]";
} }
} }

View File

@ -1,74 +0,0 @@
package org.jclouds.compute.options;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Contains options supported in the {@code ComputeService#runNode} operation. <h2>
* Usage</h2> The recommended way to instantiate a RunOptions object is to statically import
* RunOptions.* and invoke a static creation method followed by an instance mutator (if needed):
* <p/>
* <code>
* import static org.jclouds.compute.options.RunOptions.Builder.*
* <p/>
* ComputeService client = // get connection
* CreateNodeResponse client.runNode(name, template, openPorts(22, 80, 8080, 443));
* <code>
*
* @author Adrian Cole
*/
public class RunNodeOptions {
public static final RunNodeOptions NONE = new RunNodeOptions();
private int[] openPorts = new int[0];
private byte[] script;
public int[] getOpenPorts() {
return openPorts;
}
public byte[] getRunScript() {
return script;
}
/**
* This script will be executed as the root user upon system startup.
*/
public RunNodeOptions runScript(byte[] script) {
checkArgument(checkNotNull(script, "script").length <= 16 * 1024,
"script cannot be larger than 16kb");
this.script = script;
return this;
}
/**
* Opens the set of ports to public access.
*/
public RunNodeOptions openPorts(int... ports) {
this.openPorts = ports;
return this;
}
public static class Builder {
/**
* @see RunNodeOptions#openPorts
*/
public static RunNodeOptions openPorts(int... ports) {
RunNodeOptions options = new RunNodeOptions();
return options.openPorts(ports);
}
/**
* @see RunNodeOptions#runScript
*/
public static RunNodeOptions runScript(byte[] script) {
RunNodeOptions options = new RunNodeOptions();
return options.runScript(script);
}
}
}

View File

@ -0,0 +1,73 @@
package org.jclouds.compute.options;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Contains options supported in the {@code ComputeService#runNode} operation. <h2>
* Usage</h2> The recommended way to instantiate a TemplateOptions object is to statically import
* TemplateOptions.* and invoke a static creation method followed by an instance mutator (if needed):
* <p/>
* <code>
* import static org.jclouds.compute.options.TemplateOptions.Builder.*;
* <p/>
* ComputeService client = // get connection
* NodeSet set = client.runNode(name, template.options(inboundPorts(22, 80, 8080, 443)));
* <code>
*
* @author Adrian Cole
*/
public class TemplateOptions {
public static final TemplateOptions NONE = new TemplateOptions();
private int[] inboundPorts = new int[] { 22 };
private byte[] script;
public int[] getInboundPorts() {
return inboundPorts;
}
public byte[] getRunScript() {
return script;
}
/**
* This script will be executed as the root user upon system startup.
*/
public TemplateOptions runScript(byte[] script) {
checkArgument(checkNotNull(script, "script").length <= 16 * 1024,
"script cannot be larger than 16kb");
this.script = script;
return this;
}
/**
* Opens the set of ports to public access.
*/
public TemplateOptions inboundPorts(int... ports) {
this.inboundPorts = ports;
return this;
}
public static class Builder {
/**
* @see TemplateOptions#inboundPorts
*/
public static TemplateOptions inboundPorts(int... ports) {
TemplateOptions options = new TemplateOptions();
return options.inboundPorts(ports);
}
/**
* @see TemplateOptions#runScript
*/
public static TemplateOptions runScript(byte[] script) {
TemplateOptions options = new TemplateOptions();
return options.runScript(script);
}
}
}

View File

@ -22,17 +22,20 @@ import static com.google.common.base.Preconditions.checkState;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.net.ConnectException; import java.net.ConnectException;
import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.Comparator;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Named; import javax.inject.Named;
import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.CreateNodeResponse; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshClient;
import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
@ -50,6 +53,13 @@ public class ComputeUtils {
private SshClient.Factory sshFactory; private SshClient.Factory sshFactory;
private final Predicate<InetSocketAddress> socketTester; private final Predicate<InetSocketAddress> socketTester;
public static Function<ComputeMetadata, String> METADATA_TO_ID = new Function<ComputeMetadata, String>() {
@Override
public String apply(ComputeMetadata from) {
return from.getId();
}
};
@Inject @Inject
public ComputeUtils(Predicate<InetSocketAddress> socketTester) { public ComputeUtils(Predicate<InetSocketAddress> socketTester) {
this.socketTester = socketTester; this.socketTester = socketTester;
@ -65,10 +75,20 @@ public class ComputeUtils {
}); });
} }
public void runScriptOnNode(CreateNodeResponse node, byte[] script) { public static final Comparator<InetAddress> ADDRESS_COMPARATOR = new Comparator<InetAddress>() {
@Override
public int compare(InetAddress o1, InetAddress o2) {
return (o1 == o2) ? 0 : o1.getHostAddress().compareTo(o2.getHostAddress());
}
};
public void runScriptOnNode(NodeMetadata node, byte[] script) {
checkState(this.sshFactory != null, "runScript requested, but no SshModule configured"); checkState(this.sshFactory != null, "runScript requested, but no SshModule configured");
InetSocketAddress socket = new InetSocketAddress(node.getPublicAddresses().last(), 22); InetSocketAddress socket = new InetSocketAddress(Iterables.get(node.getPublicAddresses(), 0),
22);
socketTester.apply(socket); socketTester.apply(socket);
SshClient ssh = isKeyAuth(node) ? sshFactory.create(socket, node.getCredentials().account, SshClient ssh = isKeyAuth(node) ? sshFactory.create(socket, node.getCredentials().account,
node.getCredentials().key.getBytes()) : sshFactory.create(socket, node node.getCredentials().key.getBytes()) : sshFactory.create(socket, node
@ -96,7 +116,7 @@ public class ComputeUtils {
} }
} }
private void runScriptOnNodeWithClient(SshClient ssh, CreateNodeResponse node, byte[] script) { private void runScriptOnNodeWithClient(SshClient ssh, NodeMetadata node, byte[] script) {
String scriptName = node.getId() + ".sh"; String scriptName = node.getId() + ".sh";
ssh.put(scriptName, new ByteArrayInputStream(script)); ssh.put(scriptName, new ByteArrayInputStream(script));
ssh.exec("chmod 755 " + scriptName); ssh.exec("chmod 755 " + scriptName);
@ -114,7 +134,7 @@ public class ComputeUtils {
} }
} }
public static boolean isKeyAuth(CreateNodeResponse createdNode) { public static boolean isKeyAuth(NodeMetadata createdNode) {
return createdNode.getCredentials().key != null return createdNode.getCredentials().key != null
&& createdNode.getCredentials().key.startsWith("-----BEGIN RSA PRIVATE KEY-----"); && createdNode.getCredentials().key.startsWith("-----BEGIN RSA PRIVATE KEY-----");
} }

View File

@ -25,20 +25,23 @@ import static org.testng.Assert.assertNotNull;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.SortedSet;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.ComputeType; import org.jclouds.compute.domain.ComputeType;
import org.jclouds.compute.domain.CreateNodeResponse;
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.NodeSet;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.Size; import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.options.RunNodeOptions; import org.jclouds.domain.Location;
import org.jclouds.http.HttpResponseException; import org.jclouds.http.HttpResponseException;
import org.jclouds.logging.log4j.config.Log4JLoggingModule; import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.predicates.RetryablePredicate; import org.jclouds.predicates.RetryablePredicate;
@ -56,6 +59,7 @@ import org.testng.annotations.Test;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.google.inject.Module; import com.google.inject.Module;
@ -71,11 +75,10 @@ public abstract class BaseComputeServiceLiveTest {
protected String service; protected String service;
protected SshClient.Factory sshFactory; protected SshClient.Factory sshFactory;
protected RunNodeOptions options = RunNodeOptions.Builder.openPorts(22); protected String tag;
protected String nodeName;
private RetryablePredicate<InetSocketAddress> socketTester; private RetryablePredicate<InetSocketAddress> socketTester;
private CreateNodeResponse node; private SortedSet<NodeMetadata> nodes;
protected ComputeServiceContext context; protected ComputeServiceContext context;
protected ComputeService client; protected ComputeService client;
protected String user; protected String user;
@ -85,7 +88,8 @@ public abstract class BaseComputeServiceLiveTest {
@BeforeGroups(groups = { "live" }) @BeforeGroups(groups = { "live" })
public void setupClient() throws InterruptedException, ExecutionException, TimeoutException, public void setupClient() throws InterruptedException, ExecutionException, TimeoutException,
IOException { IOException {
if (nodeName == null) nodeName = checkNotNull(service, "service"); if (tag == null)
tag = checkNotNull(service, "service");
user = checkNotNull(System.getProperty("jclouds.test.user"), "jclouds.test.user"); user = checkNotNull(System.getProperty("jclouds.test.user"), "jclouds.test.user");
password = checkNotNull(System.getProperty("jclouds.test.key"), "jclouds.test.key"); password = checkNotNull(System.getProperty("jclouds.test.key"), "jclouds.test.key");
context = new ComputeServiceContextFactory().createContext(service, user, password, context = new ComputeServiceContextFactory().createContext(service, user, password,
@ -108,12 +112,7 @@ public abstract class BaseComputeServiceLiveTest {
@Test(enabled = true) @Test(enabled = true)
public void testCreate() throws Exception { public void testCreate() throws Exception {
try { try {
client.destroyNode(Iterables.find(client.listNodes(), new Predicate<ComputeMetadata>() { client.destroyNodes(tag);
@Override
public boolean apply(ComputeMetadata input) {
return input.getName().equals(nodeName);
}
}));
} catch (HttpResponseException e) { } catch (HttpResponseException e) {
// TODO hosting.com throws 400 when we try to delete a vApp // TODO hosting.com throws 400 when we try to delete a vApp
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
@ -122,75 +121,133 @@ public abstract class BaseComputeServiceLiveTest {
template = buildTemplate(client.templateBuilder()); template = buildTemplate(client.templateBuilder());
if (canRunScript(template)) if (canRunScript(template))
options.runScript(new ScriptBuilder() template
.getOptions()
.runScript(
new ScriptBuilder()
// update add dns and install jdk // update add dns and install jdk
.addStatement( .addStatement(
Statements.exec("echo nameserver 208.67.222.222 >> /etc/resolv.conf")) Statements
.addStatement(Statements.exec("apt-get update"))// .exec("echo nameserver 208.67.222.222 >> /etc/resolv.conf"))
.addStatement(Statements.exec("apt-get upgrade -y"))// .addStatement(Statements.exec("apt-get update"))
.addStatement(Statements.exec("apt-get install -y openjdk-6-jdk"))// //
.addStatement(Statements.exec("wget -qO/usr/bin/runurl run.alestic.com/runurl"))// .addStatement(Statements.exec("apt-get upgrade -y"))
.addStatement(Statements.exec("chmod 755 /usr/bin/runurl"))// //
.build(org.jclouds.scriptbuilder.domain.OsFamily.UNIX).getBytes()); .addStatement(
node = client.runNode(nodeName, template, options); Statements.exec("apt-get install -y openjdk-6-jdk"))
//
.addStatement(
Statements
.exec("wget -qO/usr/bin/runurl run.alestic.com/runurl"))
//
.addStatement(Statements.exec("chmod 755 /usr/bin/runurl"))
//
.build(org.jclouds.scriptbuilder.domain.OsFamily.UNIX)
.getBytes());
nodes = Sets.newTreeSet(client.runNodes(tag, 2, template));
assertEquals(nodes.size(), 2);
for (NodeMetadata node : nodes) {
assertNotNull(node.getId()); assertNotNull(node.getId());
assertNotNull(node.getName()); assertNotNull(node.getTag());
assert node.getPublicAddresses().size() >= 1: "no public ips in" + node; assertEquals(node.getTag(), tag);
assert node.getPublicAddresses().size() >= 1 || node.getPrivateAddresses().size() >= 1 : "no ips in"
+ node;
assertNotNull(node.getCredentials()); assertNotNull(node.getCredentials());
if (node.getCredentials().account != null) { if (node.getCredentials().account != null) {
assertNotNull(node.getCredentials().account); assertNotNull(node.getCredentials().account);
assertNotNull(node.getCredentials().key); assertNotNull(node.getCredentials().key);
sshPing(); sshPing(node);
} }
} }
NodeMetadata node1 = nodes.first();
NodeMetadata node2 = nodes.last();
// credentials aren't always the same
// assertEquals(node1.getCredentials(), node2.getCredentials());
assert !node1.getId().equals(node2.getId());
}
protected abstract Template buildTemplate(TemplateBuilder templateBuilder); protected abstract Template buildTemplate(TemplateBuilder templateBuilder);
@Test(enabled = true, dependsOnMethods = "testCreate") @Test(enabled = true, dependsOnMethods = "testCreate")
public void testGet() throws Exception { public void testGet() throws Exception {
NodeSet metadataSet = client.getNodes(tag);
for (NodeMetadata node : nodes) {
metadataSet.remove(node);
NodeMetadata metadata = client.getNodeMetadata(node); NodeMetadata metadata = client.getNodeMetadata(node);
assertEquals(metadata.getId(), node.getId()); assertEquals(metadata.getId(), node.getId());
assertEquals(metadata.getName(), node.getName()); assertEquals(metadata.getName(), node.getName());
assertEquals(metadata.getPrivateAddresses(), node.getPrivateAddresses()); assertEquals(metadata.getPrivateAddresses(), node.getPrivateAddresses());
assertEquals(metadata.getPublicAddresses(), node.getPublicAddresses()); assertEquals(metadata.getPublicAddresses(), node.getPublicAddresses());
} }
assert Iterables.all(metadataSet, new Predicate<NodeMetadata>() {
@Override
public boolean apply(NodeMetadata input) {
return input.getState() == NodeState.TERMINATED;
}
}) : metadataSet;
}
public void testListNodes() throws Exception { public void testListNodes() throws Exception {
for (ComputeMetadata node : client.listNodes()) { for (Entry<String, ? extends ComputeMetadata> node : client.getNodes().entrySet()) {
assert node.getId() != null; assertEquals(node.getKey(), node.getValue().getId());
assert node.getLocation() != null; assert node.getValue().getId() != null;
assertEquals(node.getType(), ComputeType.NODE); assert node.getValue().getLocationId() != null;
assertEquals(node.getValue().getType(), ComputeType.NODE);
} }
} }
public void testListImages() throws Exception { public void testListImages() throws Exception {
for (Image image : client.listImages()) { for (Entry<String, ? extends Image> image : client.getImages().entrySet()) {
assert image.getId() != null : image; assertEquals(image.getKey(), image.getValue().getId());
assert image.getLocation() != null : image; assert image.getValue().getId() != null : image;
assert image.getValue().getLocationId() != null : image;
assertEquals(image.getValue().getType(), ComputeType.IMAGE);
}
}
public void testListLocations() throws Exception {
for (Entry<String, ? extends Location> image : client.getLocations().entrySet()) {
assertEquals(image.getKey(), image.getValue().getId());
assert image.getValue().getId() != null : image;
assert image.getValue().getId() != image.getValue().getParent() : image;
assert image.getValue().getScope() != null : image;
} }
} }
public void testListSizes() throws Exception { public void testListSizes() throws Exception {
for (Size size : client.listSizes()) { for (Entry<String, ? extends Size> size : client.getSizes().entrySet()) {
assert size.getCores() > 0 : size; assertEquals(size.getKey(), size.getValue().getId());
assert size.getValue().getId() != null;
assert size.getValue().getCores() > 0;
assert size.getValue().getDisk() > 0;
assert size.getValue().getRam() > 0;
assert size.getValue().getSupportedArchitectures() != null;
assertEquals(size.getValue().getType(), ComputeType.SIZE);
} }
} }
private void sshPing() throws IOException { private void sshPing(NodeMetadata node) throws IOException {
for (int i = 0; i < 5; i++) {// retry loop TODO replace with predicate.
try { try {
doCheckKey(); doCheckKey(node);
} catch (SshException e) {// try twice in case there is a network timeout return;
} catch (SshException e) {
try { try {
Thread.sleep(10 * 1000); Thread.sleep(10 * 1000);
} catch (InterruptedException e1) { } catch (InterruptedException e1) {
} }
doCheckKey(); continue;
}
} }
} }
private void doCheckKey() throws IOException { private void doCheckKey(NodeMetadata node) throws IOException {
InetSocketAddress socket = new InetSocketAddress(node.getPublicAddresses().last(), 22); InetSocketAddress socket = new InetSocketAddress(Iterables.get(node.getPublicAddresses(), 0),
socketTester.apply(socket); 22);
socketTester.apply(socket); // TODO add transitionTo option that accepts a socket conection
// state.
SshClient ssh = node.getCredentials().key.startsWith("-----BEGIN RSA PRIVATE KEY-----") ? sshFactory SshClient ssh = node.getCredentials().key.startsWith("-----BEGIN RSA PRIVATE KEY-----") ? sshFactory
.create(socket, node.getCredentials().account, node.getCredentials().key.getBytes()) .create(socket, node.getCredentials().account, node.getCredentials().key.getBytes())
: sshFactory : sshFactory
@ -209,8 +266,12 @@ public abstract class BaseComputeServiceLiveTest {
@AfterTest @AfterTest
protected void cleanup() throws InterruptedException, ExecutionException, TimeoutException { protected void cleanup() throws InterruptedException, ExecutionException, TimeoutException {
if (node != null) if (nodes != null) {
client.destroyNode(node); client.destroyNodes(tag);
for (NodeMetadata node : client.getNodes(tag)) {
assert node.getState() == NodeState.TERMINATED : node;
}
}
context.close(); context.close();
} }

View File

@ -101,9 +101,9 @@ public class ConcurrentUtils {
} }
private static String message(String prefix, int size, int complete, int errors, long start) { private static String message(String prefix, int size, int complete, int errors, long start) {
return String.format("%s, completed: %d/%d, errors: %d, rate: %f ops/sec%n", prefix, return String
complete, size, errors, ((double) complete) .format("%s, completed: %d/%d, errors: %d, rate: %fms/op%n", prefix, complete,
/ ((System.currentTimeMillis() - start) / 1000.0)); size, errors, ((System.currentTimeMillis() - start) / ((double) size)));
} }
protected static boolean timeOut(long start, Long maxTime) { protected static boolean timeOut(long start, Long maxTime) {

View File

@ -0,0 +1,62 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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.domain;
/**
* Running Operating system
*
* @author Adrian Cole
*/
public interface Location {
/**
* Scope of the location, ex. region, datacenter
*
*/
LocationScope getScope();
/**
* Unique ID provided by the provider (us-standard, miami, etc)
*
*/
String getId();
/**
* Description of the location
*/
String getDescription();
/**
* The Id of the parent, or null, if top-level
*/
String getParent();
/**
* Whether nodes can be assigned to this location. It is possible that a location is a container
* type that cannot be assigned to, or that a location is full.
*/
boolean isAssignable();
}

View File

@ -0,0 +1,30 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package org.jclouds.domain;
/**
* The scope of the location
*
* @author Adrian Cole
*/
public enum LocationScope {
REGION, ZONE, RACK, HOST;
}

View File

@ -51,7 +51,7 @@ public interface MutableResourceMetadata<T extends Enum<T>> extends ResourceMeta
/** /**
* @see #getLocation * @see #getLocation
*/ */
void setLocation(String location); void setLocationId(String location);
/** /**
* @see #getUri * @see #getUri

View File

@ -1,21 +0,0 @@
package org.jclouds.domain;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
/**
* Related to the location of a resource
*
* @author Adrian Cole
*
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Qualifier
public @interface ResourceLocation {
}

View File

@ -52,12 +52,12 @@ public interface ResourceMetadata<T extends Enum<T>> extends Comparable<Resource
String getName(); String getName();
/** /**
* Physical location of the resource. * Physical location of the resource, or null if n/a
* *
* ex. us-west-1 * ex. us-west-1
* *
*/ */
String getLocation(); String getLocationId();
/** /**
* URI used to access this resource * URI used to access this resource
@ -69,4 +69,5 @@ public interface ResourceMetadata<T extends Enum<T>> extends Comparable<Resource
*/ */
Map<String, String> getUserMetadata(); Map<String, String> getUserMetadata();
} }

View File

@ -0,0 +1,127 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package org.jclouds.domain.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.Serializable;
import javax.annotation.Nullable;
import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope;
/**
* Idpayload of the object
*
* @author Adrian Cole
*/
public class LocationImpl implements Location, Serializable {
/** The serialVersionUID */
private static final long serialVersionUID = -280558162576368264L;
private final LocationScope scope;
private final String id;
private final String description;
private final String parent;
private final boolean assignable;
public LocationImpl(LocationScope scope, String id, String description, @Nullable String parent,
boolean assignable) {
this.scope = checkNotNull(scope, "scope");
this.id = checkNotNull(id, "id");
this.description = checkNotNull(description, "description");
this.parent = parent;
this.assignable = checkNotNull(assignable, "assignable");
}
public LocationScope getScope() {
return scope;
}
public String getId() {
return id;
}
public String getDescription() {
return description;
}
public String getParent() {
return parent;
}
public boolean isAssignable() {
return assignable;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (assignable ? 1231 : 1237);
result = prime * result + ((description == null) ? 0 : description.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((parent == null) ? 0 : parent.hashCode());
result = prime * result + ((scope == null) ? 0 : scope.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LocationImpl other = (LocationImpl) obj;
if (assignable != other.assignable)
return false;
if (description == null) {
if (other.description != null)
return false;
} else if (!description.equals(other.description))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (parent == null) {
if (other.parent != null)
return false;
} else if (!parent.equals(other.parent))
return false;
if (scope == null) {
if (other.scope != null)
return false;
} else if (!scope.equals(other.scope))
return false;
return true;
}
@Override
public String toString() {
return "[id=" + id + ", scope=" + scope + ", description=" + description + ", parent="
+ parent + ", assignable=" + assignable + "]";
}
}

View File

@ -57,7 +57,7 @@ public class MutableResourceMetadataImpl<T extends Enum<T>> implements MutableRe
this.type = from.getType(); this.type = from.getType();
this.id = from.getId(); this.id = from.getId();
this.name = from.getName(); this.name = from.getName();
this.location = from.getLocation(); this.location = from.getLocationId();
this.uri = from.getUri(); this.uri = from.getUri();
this.userMetadata = from.getUserMetadata(); this.userMetadata = from.getUserMetadata();
} }
@ -156,7 +156,7 @@ public class MutableResourceMetadataImpl<T extends Enum<T>> implements MutableRe
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public void setLocation(String location) { public void setLocationId(String location) {
this.location = location; this.location = location;
} }
@ -164,7 +164,7 @@ public class MutableResourceMetadataImpl<T extends Enum<T>> implements MutableRe
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public String getLocation() { public String getLocationId() {
return location; return location;
} }

View File

@ -45,17 +45,17 @@ public class ResourceMetadataImpl<T extends Enum<T>> implements ResourceMetadata
@Nullable @Nullable
private final String name; private final String name;
@Nullable @Nullable
private final String location; private final String locationId;
@Nullable @Nullable
private final URI uri; private final URI uri;
private final Map<String, String> userMetadata = Maps.newLinkedHashMap(); private final Map<String, String> userMetadata = Maps.newLinkedHashMap();
public ResourceMetadataImpl(T type, @Nullable String id, @Nullable String name, public ResourceMetadataImpl(T type, @Nullable String id, @Nullable String name,
@Nullable String location, @Nullable URI uri, Map<String, String> userMetadata) { @Nullable String locationId, @Nullable URI uri, Map<String, String> userMetadata) {
this.type = checkNotNull(type, "type"); this.type = checkNotNull(type, "type");
this.id = id; this.id = id;
this.name = name; this.name = name;
this.location = location; this.locationId = locationId;
this.uri = uri; this.uri = uri;
this.userMetadata.putAll(checkNotNull(userMetadata, "userMetadata")); this.userMetadata.putAll(checkNotNull(userMetadata, "userMetadata"));
} }
@ -98,8 +98,8 @@ public class ResourceMetadataImpl<T extends Enum<T>> implements ResourceMetadata
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public String getLocation() { public String getLocationId() {
return location; return locationId;
} }
/** /**
@ -123,7 +123,7 @@ public class ResourceMetadataImpl<T extends Enum<T>> implements ResourceMetadata
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode()); result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((location == null) ? 0 : location.hashCode()); result = prime * result + ((locationId == null) ? 0 : locationId.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((type == null) ? 0 : type.hashCode()); result = prime * result + ((type == null) ? 0 : type.hashCode());
result = prime * result + ((uri == null) ? 0 : uri.hashCode()); result = prime * result + ((uri == null) ? 0 : uri.hashCode());
@ -145,10 +145,10 @@ public class ResourceMetadataImpl<T extends Enum<T>> implements ResourceMetadata
return false; return false;
} else if (!id.equals(other.id)) } else if (!id.equals(other.id))
return false; return false;
if (location == null) { if (locationId == null) {
if (other.location != null) if (other.locationId != null)
return false; return false;
} else if (!location.equals(other.location)) } else if (!locationId.equals(other.locationId))
return false; return false;
if (name == null) { if (name == null) {
if (other.name != null) if (other.name != null)
@ -175,7 +175,7 @@ public class ResourceMetadataImpl<T extends Enum<T>> implements ResourceMetadata
@Override @Override
public String toString() { public String toString() {
return "[type=" + type + ", id=" + id + ", name=" + name + ", location=" + location return "[type=" + type + ", id=" + id + ", name=" + name + ", locationId=" + locationId
+ ", uri=" + uri + ", userMetadata=" + userMetadata + "]"; + ", uri=" + uri + ", userMetadata=" + userMetadata + "]";
} }

View File

@ -20,9 +20,16 @@ package org.jclouds.rackspace.cloudservers.compute;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.compute.util.ComputeUtils.METADATA_TO_ID;
import static org.jclouds.concurrent.ConcurrentUtils.awaitCompletion;
import static org.jclouds.concurrent.ConcurrentUtils.makeListenable;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
@ -30,71 +37,96 @@ import javax.inject.Named;
import javax.inject.Provider; import javax.inject.Provider;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeService;
import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.ComputeType; import org.jclouds.compute.domain.ComputeType;
import org.jclouds.compute.domain.CreateNodeResponse;
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.NodeSet;
import org.jclouds.compute.domain.NodeState; import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.Size; import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.domain.internal.CreateNodeResponseImpl;
import org.jclouds.compute.domain.internal.NodeMetadataImpl; import org.jclouds.compute.domain.internal.NodeMetadataImpl;
import org.jclouds.compute.options.RunNodeOptions; import org.jclouds.compute.domain.internal.NodeSetImpl;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.util.ComputeUtils; import org.jclouds.compute.util.ComputeUtils;
import org.jclouds.concurrent.ConcurrentUtils;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.domain.ResourceLocation; import org.jclouds.domain.Location;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rackspace.cloudservers.CloudServersClient; import org.jclouds.rackspace.cloudservers.CloudServersClient;
import org.jclouds.rackspace.cloudservers.compute.domain.CloudServersImage;
import org.jclouds.rackspace.cloudservers.compute.domain.CloudServersSize;
import org.jclouds.rackspace.cloudservers.domain.Server; import org.jclouds.rackspace.cloudservers.domain.Server;
import org.jclouds.rackspace.cloudservers.domain.ServerStatus; import org.jclouds.rackspace.cloudservers.domain.ServerStatus;
import org.jclouds.rackspace.cloudservers.options.ListOptions; import org.jclouds.rackspace.cloudservers.options.ListOptions;
import org.jclouds.rackspace.reference.RackspaceConstants;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.util.concurrent.ListenableFuture;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Singleton
public class CloudServersComputeService implements ComputeService { public class CloudServersComputeService implements ComputeService {
private static class NodeMatchesTag implements Predicate<NodeMetadata> {
private final String tag;
@Override
public boolean apply(NodeMetadata from) {
return from.getTag().equals(tag);
}
public NodeMatchesTag(String tag) {
super();
this.tag = tag;
}
};
@Resource @Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER) @Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
private final org.jclouds.rackspace.cloudservers.CloudServersClient client; private final org.jclouds.rackspace.cloudservers.CloudServersClient client;
protected final Provider<Set<? extends Image>> images; protected final Provider<Map<String, ? extends Image>> images;
protected final Provider<Set<? extends Size>> sizes; protected final Provider<Map<String, ? extends Size>> sizes;
protected final Provider<Map<String, ? extends Location>> locations;
protected final Provider<TemplateBuilder> templateBuilderProvider; protected final Provider<TemplateBuilder> templateBuilderProvider;
private final String location;
private final ComputeUtils utils; private final ComputeUtils utils;
private final Predicate<Server> serverActive; private final Predicate<Server> serverActive;
private final ServerToNodeMetadata serverToNodeMetadata; private final ServerToNodeMetadata serverToNodeMetadata;
private final Predicate<Server> serverDeleted; private final Predicate<Server> serverDeleted;
protected final ExecutorService executor;
private final String account;
@Inject @Inject
public CloudServersComputeService(CloudServersClient client, public CloudServersComputeService(CloudServersClient client,
Provider<TemplateBuilder> templateBuilderProvider, @ResourceLocation String location, Provider<TemplateBuilder> templateBuilderProvider,
Provider<Set<? extends Image>> images, Provider<Set<? extends Size>> sizes, Provider<Map<String, ? extends Image>> images,
ComputeUtils utils, @Named("ACTIVE") Predicate<Server> serverActive, Provider<Map<String, ? extends Size>> sizes,
Provider<Map<String, ? extends Location>> locations, ComputeUtils utils,
@Named("ACTIVE") Predicate<Server> serverActive,
@Named("DELETED") Predicate<Server> serverDeleted, @Named("DELETED") Predicate<Server> serverDeleted,
ServerToNodeMetadata serverToNodeMetadata) { @Named(RackspaceConstants.PROPERTY_RACKSPACE_USER) String account,
this.location = location; ServerToNodeMetadata serverToNodeMetadata,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
this.client = client; this.client = client;
this.images = images; this.images = images;
this.sizes = sizes; this.sizes = sizes;
this.locations = locations;
this.utils = utils; this.utils = utils;
this.templateBuilderProvider = templateBuilderProvider; this.templateBuilderProvider = templateBuilderProvider;
this.serverActive = serverActive; this.serverActive = serverActive;
this.serverDeleted = serverDeleted; this.serverDeleted = serverDeleted;
this.account = account;
this.serverToNodeMetadata = serverToNodeMetadata; this.serverToNodeMetadata = serverToNodeMetadata;
this.executor = executor;
} }
private static Map<ServerStatus, NodeState> serverToNodeState = ImmutableMap private static Map<ServerStatus, NodeState> serverToNodeState = ImmutableMap
@ -123,38 +155,40 @@ public class CloudServersComputeService implements ComputeService {
.put(ServerStatus.UNKNOWN, NodeState.UNKNOWN).build(); .put(ServerStatus.UNKNOWN, NodeState.UNKNOWN).build();
@Override @Override
public CreateNodeResponse runNode(String name, Template template) { public NodeSet runNodes(final String tag, int max, final Template template) {
return this.runNode(name, template, RunNodeOptions.NONE); checkArgument(tag.indexOf('-') == -1, "tag cannot contain hyphens");
} logger.debug(">> running server image(%s) flavor(%s)", template.getImage().getId(), template
.getSize().getId());
final Set<NodeMetadata> nodes = Sets.newHashSet();
Set<ListenableFuture<Void>> responses = Sets.newHashSet();
for (int i = 0; i < max; i++) {
final String name = String.format("%s-%s-%d", account, tag, i + 1);
responses.add(ConcurrentUtils.makeListenable(executor.submit(new Callable<Void>() {
@Override @Override
public CreateNodeResponse runNode(String name, Template template, RunNodeOptions options) { public Void call() throws Exception {
checkArgument(template.getImage() instanceof CloudServersImage, Server server = client.createServer(name, Integer.parseInt(template.getImage()
"unexpected image type. should be CloudServersImage, was: " .getId()), Integer.parseInt(template.getSize().getId()));
+ template.getImage().getClass());
CloudServersImage cloudServersImage = CloudServersImage.class.cast(template.getImage());
checkArgument(template.getSize() instanceof CloudServersSize,
"unexpected size type. should be CloudServersSize, was: "
+ template.getSize().getClass());
CloudServersSize cloudServersSize = CloudServersSize.class.cast(template.getSize());
logger.debug(">> running server location(%s) image(%s) flavor(%s)", location, NodeMetadata node = new NodeMetadataImpl(server.getId() + "", name, null, null,
cloudServersImage.getId(), template.getSize().getId()); server.getMetadata(), tag, NodeState.RUNNING, server.getAddresses()
.getPublicAddresses(),
Server server = client.createServer(name, cloudServersImage.getImage().getId(), server.getAddresses().getPrivateAddresses(), ImmutableMap
cloudServersSize.getFlavor().getId()); .<String, String> of(), new Credentials("root", server
.getAdminPass()));
CreateNodeResponse node = new CreateNodeResponseImpl(server.getId() + "", name, location, nodes.add(node);
null, server.getMetadata(), NodeState.RUNNING, server.getAddresses()
.getPublicAddresses(), server.getAddresses().getPrivateAddresses(),
new Credentials("root", server.getAdminPass()), ImmutableMap.<String, String> of());
logger.debug("<< started server(%s)", server.getId()); logger.debug("<< started server(%s)", server.getId());
serverActive.apply(server); serverActive.apply(server);
logger.debug("<< running server(%s)", server.getId()); logger.debug("<< running server(%s)", server.getId());
if (options.getRunScript() != null) { if (template.getOptions().getRunScript() != null) {
utils.runScriptOnNode(node, options.getRunScript()); utils.runScriptOnNode(node, template.getOptions().getRunScript());
} }
return node; return null;
}
}), executor));
}
ConcurrentUtils.awaitCompletion(responses, executor, null, logger, "nodes");
return new NodeSetImpl(nodes);
} }
@Override @Override
@ -165,33 +199,42 @@ public class CloudServersComputeService implements ComputeService {
return serverToNodeMetadata.apply(client.getServer(Integer.parseInt(node.getId()))); return serverToNodeMetadata.apply(client.getServer(Integer.parseInt(node.getId())));
} }
public static final Pattern TAG_PATTERN = Pattern.compile("[^-]+-([^-]+)-[0-9]+");
@Singleton @Singleton
private static class ServerToNodeMetadata implements Function<Server, NodeMetadata> { private static class ServerToNodeMetadata implements Function<Server, NodeMetadata> {
private final String location; private final Location location;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Inject @Inject
ServerToNodeMetadata(@ResourceLocation String location) { ServerToNodeMetadata(Location location) {
this.location = location; this.location = location;
} }
@Override @Override
public NodeMetadata apply(Server from) { public NodeMetadata apply(Server from) {
return new NodeMetadataImpl(from.getId() + "", from.getName(), location, null, from Matcher matcher = TAG_PATTERN.matcher(from.getName());
.getMetadata(), serverToNodeState.get(from.getStatus()), from.getAddresses() final String tag = matcher.find() ? matcher.group(1) : null;
.getPublicAddresses(), from.getAddresses().getPrivateAddresses(), ImmutableMap return new NodeMetadataImpl(from.getId() + "", from.getName(), location.getId(), null,
.<String, String> of()); from.getMetadata(), tag, serverToNodeState.get(from.getStatus()), from
.getAddresses().getPublicAddresses(), from.getAddresses()
.getPrivateAddresses(), ImmutableMap.<String, String> of(), null);
} }
} }
@Override @Override
public Set<ComputeMetadata> listNodes() { public Map<String, ? extends ComputeMetadata> getNodes() {
logger.debug(">> listing servers"); logger.debug(">> listing servers");
Set<ComputeMetadata> servers = Sets.newHashSet(); ImmutableMap<String, NodeMetadata> map = doGetNodes();
Iterables.addAll(servers, Iterables.transform(client.listServers(ListOptions.Builder logger.debug("<< list(%d)", map.size());
.withDetails()), serverToNodeMetadata)); return map;
logger.debug("<< list(%d)", servers.size()); }
return servers;
private ImmutableMap<String, NodeMetadata> doGetNodes() {
ImmutableMap<String, NodeMetadata> map = Maps.uniqueIndex(Iterables.transform(client
.listServers(ListOptions.Builder.withDetails()), serverToNodeMetadata),
METADATA_TO_ID);
return map;
} }
@Override @Override
@ -208,12 +251,62 @@ public class CloudServersComputeService implements ComputeService {
} }
@Override @Override
public Set<? extends Size> listSizes() { public void destroyNodes(String tag) { // TODO parallel
logger.debug(">> terminating servers by tag(%s)", tag);
Set<ListenableFuture<Void>> responses = Sets.newHashSet();
for (final NodeMetadata node : doGetNodes(tag)) {
responses.add(makeListenable(executor.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
destroyNode(node);
return null;
}
}), executor));
}
awaitCompletion(responses, executor, null, logger, "nodes");
logger.debug("<< destroyed");
}
@Override
public Map<String, ? extends Location> getLocations() {
return locations.get();
}
@Override
public NodeSet getNodes(String tag) {
logger.debug(">> listing servers by tag(%s)", tag);
NodeSet nodes = doGetNodes(tag);
logger.debug("<< list(%d)", nodes.size());
return nodes;
}
protected NodeSet doGetNodes(final String tag) {
Iterable<NodeMetadata> nodes = Iterables.filter(Iterables.transform(doGetNodes().values(),
new Function<ComputeMetadata, NodeMetadata>() {
@Override
public NodeMetadata apply(ComputeMetadata from) {
return getNodeMetadata(from);
}
}), new Predicate<NodeMetadata>() {
@Override
public boolean apply(NodeMetadata input) {
return tag.equals(input.getTag());
}
});
return new NodeSetImpl(Iterables.filter(nodes, new NodeMatchesTag(tag)));
}
@Override
public Map<String, ? extends Size> getSizes() {
return sizes.get(); return sizes.get();
} }
@Override @Override
public Set<? extends Image> listImages() { public Map<String, ? extends Image> getImages() {
return images.get(); return images.get();
} }

View File

@ -18,6 +18,7 @@
*/ */
package org.jclouds.rackspace.cloudservers.compute.config; package org.jclouds.rackspace.cloudservers.compute.config;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
@ -33,24 +34,30 @@ import org.jclouds.Constants;
import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.domain.Architecture; import org.jclouds.compute.domain.Architecture;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.Size; import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.internal.ImageImpl;
import org.jclouds.compute.domain.internal.SizeImpl;
import org.jclouds.compute.internal.ComputeServiceContextImpl; import org.jclouds.compute.internal.ComputeServiceContextImpl;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.ResourceLocation; import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope;
import org.jclouds.domain.internal.LocationImpl;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rackspace.cloudservers.CloudServersAsyncClient; import org.jclouds.rackspace.cloudservers.CloudServersAsyncClient;
import org.jclouds.rackspace.cloudservers.CloudServersClient; import org.jclouds.rackspace.cloudservers.CloudServersClient;
import org.jclouds.rackspace.cloudservers.compute.CloudServersComputeService; import org.jclouds.rackspace.cloudservers.compute.CloudServersComputeService;
import org.jclouds.rackspace.cloudservers.compute.domain.CloudServersImage;
import org.jclouds.rackspace.cloudservers.compute.domain.CloudServersSize;
import org.jclouds.rackspace.cloudservers.config.CloudServersContextModule; import org.jclouds.rackspace.cloudservers.config.CloudServersContextModule;
import org.jclouds.rackspace.cloudservers.domain.Flavor; import org.jclouds.rackspace.cloudservers.domain.Flavor;
import org.jclouds.rackspace.cloudservers.options.ListOptions; import org.jclouds.rackspace.cloudservers.options.ListOptions;
import org.jclouds.rest.RestContext; import org.jclouds.rest.RestContext;
import com.google.common.base.Function;
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.Sets; import com.google.common.collect.Sets;
import com.google.inject.Provides; import com.google.inject.Provides;
@ -78,25 +85,44 @@ public class CloudServersComputeServiceContextModule extends CloudServersContext
@Provides @Provides
@Singleton @Singleton
@ResourceLocation Location getRegion() {
String getRegion() { return new LocationImpl(LocationScope.ZONE, "DALLAS", "Dallas, TX", null, true);
return "default";
} }
@Provides @Provides
@Singleton @Singleton
protected Set<? extends Size> provideSizes(CloudServersClient sync, Set<? extends Image> images, Map<String, ? extends Location> provideLocations(Location location) {
LogHolder holder, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) return ImmutableMap.of(location.getId(), location);
throws InterruptedException, TimeoutException, ExecutionException { }
@Provides
@Singleton
protected Function<ComputeMetadata, String> indexer() {
return new Function<ComputeMetadata, String>() {
@Override
public String apply(ComputeMetadata from) {
return from.getId();
}
};
}
@Provides
@Singleton
protected Map<String, ? extends Size> provideSizes(CloudServersClient sync,
Map<String, ? extends Image> images, Location location, LogHolder holder,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor,
Function<ComputeMetadata, String> indexer) throws InterruptedException,
TimeoutException, ExecutionException {
final Set<Size> sizes = Sets.newHashSet(); final Set<Size> sizes = Sets.newHashSet();
holder.logger.debug(">> providing sizes"); holder.logger.debug(">> providing sizes");
for (final Flavor from : sync.listFlavors(ListOptions.Builder.withDetails())) { for (final Flavor from : sync.listFlavors(ListOptions.Builder.withDetails())) {
sizes.add(new CloudServersSize(from, from.getId() + "", from.getDisk() / 10, sizes.add(new SizeImpl(from.getId() + "", from.getName(), location.getId(), null,
from.getRam(), from.getDisk(), ImmutableSet.<Architecture> of( ImmutableMap.<String, String> of(), from.getDisk() / 10, from.getRam(), from
Architecture.X86_32, Architecture.X86_64))); .getDisk(), ImmutableSet.<Architecture> of(Architecture.X86_32,
Architecture.X86_64)));
} }
holder.logger.debug("<< sizes(%d)", sizes.size()); holder.logger.debug("<< sizes(%d)", sizes.size());
return sizes; return Maps.uniqueIndex(sizes, indexer);
} }
private static class LogHolder { private static class LogHolder {
@ -109,9 +135,9 @@ public class CloudServersComputeServiceContextModule extends CloudServersContext
@Provides @Provides
@Singleton @Singleton
protected Set<? extends Image> provideImages(final CloudServersClient sync, protected Map<String, ? extends Image> provideImages(final CloudServersClient sync,
@ResourceLocation String location, LogHolder holder) throws InterruptedException, Location location, LogHolder holder, Function<ComputeMetadata, String> indexer)
ExecutionException, TimeoutException { throws InterruptedException, ExecutionException, TimeoutException {
final Set<Image> images = Sets.newHashSet(); final Set<Image> images = Sets.newHashSet();
holder.logger.debug(">> providing images"); holder.logger.debug(">> providing images");
for (final org.jclouds.rackspace.cloudservers.domain.Image from : sync for (final org.jclouds.rackspace.cloudservers.domain.Image from : sync
@ -120,7 +146,6 @@ public class CloudServersComputeServiceContextModule extends CloudServersContext
Architecture arch = Architecture.X86_64; Architecture arch = Architecture.X86_64;
String osDescription = ""; String osDescription = "";
String version = ""; String version = "";
Matcher matcher = RACKSPACE_PATTERN.matcher(from.getName()); Matcher matcher = RACKSPACE_PATTERN.matcher(from.getName());
osDescription = from.getName(); osDescription = from.getName();
if (from.getName().indexOf("Red Hat EL") != -1) { if (from.getName().indexOf("Red Hat EL") != -1) {
@ -132,9 +157,11 @@ public class CloudServersComputeServiceContextModule extends CloudServersContext
holder.logger.debug("<< didn't match os(%s)", matcher.group(2)); holder.logger.debug("<< didn't match os(%s)", matcher.group(2));
} }
} }
images.add(new CloudServersImage(from, location, arch, os, osDescription, version)); images.add(new ImageImpl(from.getId() + "", from.getName(), location.getId(), null,
ImmutableMap.<String, String> of(), from.getName(), version, os, osDescription,
arch));
} }
holder.logger.debug("<< images(%d)", images.size()); holder.logger.debug("<< images(%d)", images.size());
return images; return Maps.uniqueIndex(images, indexer);
} }
} }

View File

@ -1,154 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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.rackspace.cloudservers.compute.domain;
import org.jclouds.compute.domain.Architecture;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.OsFamily;
/**
*
* @author Adrian Cole
*/
public class CloudServersImage implements Image {
private final org.jclouds.rackspace.cloudservers.domain.Image image;
private final String location;
private final Architecture architecture;
private final OsFamily os;
private final String osDescription;
private final String version;
public CloudServersImage(org.jclouds.rackspace.cloudservers.domain.Image image, String location,
Architecture architecture, OsFamily os, String osDescription, String version) {
this.location = location;
this.architecture = architecture;
this.image = image;
this.os = os;
this.osDescription = osDescription;
this.version = version;
}
@Override
public Architecture getArchitecture() {
return architecture;
}
@Override
public String getDescription() {
return getImage().getName();
}
@Override
public String getId() {
return getImage().getId()+"";
}
@Override
public String getLocation() {
return location;
}
@Override
public OsFamily getOsFamily() {
return os;
}
@Override
public String getOsDescription() {
return osDescription;
}
@Override
public String getVersion() {
return version;
}
public org.jclouds.rackspace.cloudservers.domain.Image getImage() {
return image;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((architecture == null) ? 0 : architecture.hashCode());
result = prime * result + ((image == null) ? 0 : image.hashCode());
result = prime * result + ((location == null) ? 0 : location.hashCode());
result = prime * result + ((os == null) ? 0 : os.hashCode());
result = prime * result + ((osDescription == null) ? 0 : osDescription.hashCode());
result = prime * result + ((version == null) ? 0 : version.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CloudServersImage other = (CloudServersImage) obj;
if (architecture == null) {
if (other.architecture != null)
return false;
} else if (!architecture.equals(other.architecture))
return false;
if (image == null) {
if (other.image != null)
return false;
} else if (!image.equals(other.image))
return false;
if (location == null) {
if (other.location != null)
return false;
} else if (!location.equals(other.location))
return false;
if (os == null) {
if (other.os != null)
return false;
} else if (!os.equals(other.os))
return false;
if (osDescription == null) {
if (other.osDescription != null)
return false;
} else if (!osDescription.equals(other.osDescription))
return false;
if (version == null) {
if (other.version != null)
return false;
} else if (!version.equals(other.version))
return false;
return true;
}
@Override
public String toString() {
return "[id=" + getId() + ", version=" + version + ", location=" + getLocation()
+ ", architecture=" + getArchitecture() + ", operatingSystem="
+ getOsFamily() + ", operatingSystemVersion=" + getOsDescription()
+ ", description=" + getDescription() + "]";
}
}

View File

@ -1,72 +0,0 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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.rackspace.cloudservers.compute.domain;
import org.jclouds.compute.domain.Architecture;
import org.jclouds.compute.domain.internal.SizeImpl;
import org.jclouds.rackspace.cloudservers.domain.Flavor;
/**
*
* @author Adrian Cole
*/
public class CloudServersSize extends SizeImpl {
private final Flavor flavor;
public CloudServersSize(Flavor flavor, String id, int cores, int ram, int disk,
Iterable<Architecture> supportedArchitectures) {
super(id, cores, ram, disk, supportedArchitectures);
this.flavor = flavor;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((flavor == null) ? 0 : flavor.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
CloudServersSize other = (CloudServersSize) obj;
if (flavor == null) {
if (other.flavor != null)
return false;
} else if (!flavor.equals(other.flavor))
return false;
return true;
}
public Flavor getFlavor() {
return flavor;
}
}

View File

@ -20,10 +20,17 @@ package org.jclouds.rimuhosting.miro.compute;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.compute.util.ComputeUtils.METADATA_TO_ID;
import static org.jclouds.concurrent.ConcurrentUtils.awaitCompletion;
import static org.jclouds.concurrent.ConcurrentUtils.makeListenable;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.regex.Pattern;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
@ -31,22 +38,24 @@ import javax.inject.Named;
import javax.inject.Provider; import javax.inject.Provider;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeService;
import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.ComputeType; import org.jclouds.compute.domain.ComputeType;
import org.jclouds.compute.domain.CreateNodeResponse;
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.NodeSet;
import org.jclouds.compute.domain.NodeState; import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.Size; import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.domain.internal.CreateNodeResponseImpl;
import org.jclouds.compute.domain.internal.NodeMetadataImpl; import org.jclouds.compute.domain.internal.NodeMetadataImpl;
import org.jclouds.compute.options.RunNodeOptions; import org.jclouds.compute.domain.internal.NodeSetImpl;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.util.ComputeUtils;
import org.jclouds.concurrent.ConcurrentUtils;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.domain.ResourceLocation; import org.jclouds.domain.Location;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rimuhosting.miro.RimuHostingClient; import org.jclouds.rimuhosting.miro.RimuHostingClient;
import org.jclouds.rimuhosting.miro.domain.NewServerResponse; import org.jclouds.rimuhosting.miro.domain.NewServerResponse;
@ -54,55 +63,19 @@ import org.jclouds.rimuhosting.miro.domain.Server;
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.Predicate;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.util.concurrent.ListenableFuture;
/** /**
* @author Ivan Meredith * @author Ivan Meredith
*/ */
@Singleton @Singleton
public class RimuHostingComputeService implements ComputeService { public class RimuHostingComputeService implements ComputeService {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
protected final RimuHostingClient client;
protected final Provider<Set<? extends Image>> images;
protected final Provider<Set<? extends Size>> sizes;
protected final Provider<TemplateBuilder> templateBuilderProvider;
private final String location;
@Inject
public RimuHostingComputeService(RimuHostingClient client,
Provider<TemplateBuilder> templateBuilderProvider, @ResourceLocation String location,
Provider<Set<? extends Image>> images, Provider<Set<? extends Size>> sizes) {
this.client = client;
this.location = location;
this.images = images;
this.sizes = sizes;
this.templateBuilderProvider = templateBuilderProvider;
}
@Override
public CreateNodeResponse runNode(String name, Template template) {
return this.runNode(name, template, RunNodeOptions.NONE);
}
@Override
public CreateNodeResponse runNode(String name, Template template, RunNodeOptions options) {
NewServerResponse serverResponse = client.createServer(name, checkNotNull(template.getImage()
.getId(), "imageId"), checkNotNull(template.getSize().getId(), "sizeId"));
return new CreateNodeResponseImpl(serverResponse.getServer().getId().toString(),
name, location, null, ImmutableMap.<String, String> of(), NodeState.UNKNOWN,// TODO
// need a
// real
// state!
getPublicAddresses(serverResponse.getServer()),// no real useful data here..
ImmutableList.<InetAddress> of(), new Credentials("root", serverResponse
.getNewInstanceRequest().getCreateOptions().getPassword()), ImmutableMap
.<String, String> of());
}
@VisibleForTesting @VisibleForTesting
static Iterable<InetAddress> getPublicAddresses(Server server) { static Iterable<InetAddress> getPublicAddresses(Server server) {
@ -122,20 +95,91 @@ public class RimuHostingComputeService implements ComputeService {
}); });
} }
public Set<ComputeMetadata> listNodes() { private static class NodeMatchesTag implements Predicate<NodeMetadata> {
Set<ComputeMetadata> serverSet = Sets.newLinkedHashSet(); private final String tag;
Set<Server> servers = client.getServerList();
for (Server server : servers) { @Override
serverSet.add(toNode(server)); public boolean apply(NodeMetadata from) {
} return from.getTag().equals(tag);
return serverSet;
} }
private NodeMetadataImpl toNode(Server server) { public NodeMatchesTag(String tag) {
return new NodeMetadataImpl(server.getId() + "", server.getName(), location, null, super();
ImmutableMap.<String, String> of(), NodeState.UNKNOWN, getPublicAddresses(server), this.tag = tag;
ImmutableList.<InetAddress> of(), ImmutableMap.<String, String> of("state", server }
.getState())); };
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
private final RimuHostingClient client;
protected final Provider<Map<String, ? extends Image>> images;
protected final Provider<Map<String, ? extends Size>> sizes;
protected final Provider<Map<String, ? extends Location>> locations;
protected final Provider<TemplateBuilder> templateBuilderProvider;
private final ComputeUtils utils;
private final ServerToNodeMetadata serverToNodeMetadata;
protected final ExecutorService executor;
@Inject
public RimuHostingComputeService(RimuHostingClient client,
Provider<TemplateBuilder> templateBuilderProvider,
Provider<Map<String, ? extends Image>> images,
Provider<Map<String, ? extends Size>> sizes, ServerToNodeMetadata serverToNodeMetadata,
Provider<Map<String, ? extends Location>> locations, ComputeUtils utils,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
this.client = client;
this.images = images;
this.sizes = sizes;
this.locations = locations;
this.utils = utils;
this.templateBuilderProvider = templateBuilderProvider;
this.serverToNodeMetadata = serverToNodeMetadata;
this.executor = executor;
}
@Override
public NodeSet runNodes(final String tag, int max, final Template template) {
checkArgument(tag.indexOf('-') == -1, "tag cannot contain hyphens");
logger.debug(">> running server image(%s) flavor(%s)", template.getImage().getId(), template
.getSize().getId());
final Set<NodeMetadata> nodes = Sets.newHashSet();
Set<ListenableFuture<Void>> responses = Sets.newHashSet();
for (int i = 0; i < max; i++) {
final String name = String.format("%s-%d", tag, i + 1);
responses.add(ConcurrentUtils.makeListenable(executor.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
NewServerResponse serverResponse = client.createServer(name, checkNotNull(template
.getImage().getId(), "imageId"), checkNotNull(template.getSize().getId(),
"sizeId"));
NodeMetadata node = new NodeMetadataImpl(serverResponse.getServer().getId()
.toString(), name, template.getLocation().getId(),
null,
ImmutableMap.<String, String> of(),
tag,
NodeState.UNKNOWN,// TODO
// need a
// real
// state!
getPublicAddresses(serverResponse.getServer()),// no real useful data here..
ImmutableList.<InetAddress> of(), ImmutableMap.<String, String> of(),
new Credentials("root", serverResponse.getNewInstanceRequest()
.getCreateOptions().getPassword()));
nodes.add(node);
logger.debug("<< started server(%s)", node.getId());
// TODO! serverActive.apply(server);
logger.debug("<< running server(%s)", node.getId());
if (template.getOptions().getRunScript() != null) {
utils.runScriptOnNode(node, template.getOptions().getRunScript());
}
return null;
}
}), executor));
}
ConcurrentUtils.awaitCompletion(responses, executor, null, logger, "nodes");
return new NodeSetImpl(nodes);
} }
@Override @Override
@ -143,7 +187,7 @@ public class RimuHostingComputeService implements ComputeService {
checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not " checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not "
+ node.getType()); + node.getType());
checkNotNull(node.getId(), "node.id"); checkNotNull(node.getId(), "node.id");
return toNode(client.getServer(Long.parseLong(node.getId()))); return serverToNodeMetadata.apply(client.getServer(Long.parseLong(node.getId())));
} }
@Override @Override
@ -151,21 +195,110 @@ public class RimuHostingComputeService implements ComputeService {
checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not " checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not "
+ node.getType()); + node.getType());
checkNotNull(node.getId(), "node.id"); checkNotNull(node.getId(), "node.id");
checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not "
+ node.getType());
checkNotNull(node.getId(), "node.id");
logger.debug(">> deleting server(%s)", node.getId());
client.destroyServer(new Long(node.getId())); client.destroyServer(new Long(node.getId()));
logger.debug("<< deleted server(%s)", node.getId());
}
public static final Pattern TAG_PATTERN = Pattern.compile("[^-]+-([^-]+)-[0-9]+");
@Singleton
private static class ServerToNodeMetadata implements Function<Server, NodeMetadata> {
@Override
public NodeMetadata apply(Server from) {
String locationId = "//TODO";
String tag = from.getName().replaceAll("-[0-9]+", "");
Credentials creds = null;
NodeState state = NodeState.UNKNOWN;
return new NodeMetadataImpl(from.getId() + "", from.getName(), locationId, null,
ImmutableMap.<String, String> of(), tag, state, getPublicAddresses(from),
ImmutableList.<InetAddress> of(), ImmutableMap.<String, String> of("state", from
.getState()), creds);
}
} }
@Override @Override
public Set<? extends Size> listSizes() { public Map<String, ? extends ComputeMetadata> getNodes() {
logger.debug(">> listing servers");
ImmutableMap<String, NodeMetadata> map = doGetNodes();
logger.debug("<< list(%d)", map.size());
return map;
}
private ImmutableMap<String, NodeMetadata> doGetNodes() {
ImmutableMap<String, NodeMetadata> map = Maps.uniqueIndex(Iterables.transform(client
.getServerList(), serverToNodeMetadata), METADATA_TO_ID);
return map;
}
@Override
public void destroyNodes(String tag) { // TODO parallel
logger.debug(">> terminating servers by tag(%s)", tag);
Set<ListenableFuture<Void>> responses = Sets.newHashSet();
for (final NodeMetadata node : doGetNodes(tag)) {
responses.add(makeListenable(executor.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
destroyNode(node);
return null;
}
}), executor));
}
awaitCompletion(responses, executor, null, logger, "nodes");
logger.debug("<< destroyed");
}
@Override
public Map<String, ? extends Location> getLocations() {
return locations.get();
}
@Override
public NodeSet getNodes(String tag) {
logger.debug(">> listing servers by tag(%s)", tag);
NodeSet nodes = doGetNodes(tag);
logger.debug("<< list(%d)", nodes.size());
return nodes;
}
protected NodeSet doGetNodes(final String tag) {
Iterable<NodeMetadata> nodes = Iterables.filter(Iterables.transform(doGetNodes().values(),
new Function<ComputeMetadata, NodeMetadata>() {
@Override
public NodeMetadata apply(ComputeMetadata from) {
return getNodeMetadata(from);
}
}), new Predicate<NodeMetadata>() {
@Override
public boolean apply(NodeMetadata input) {
return tag.equals(input.getTag());
}
});
return new NodeSetImpl(Iterables.filter(nodes, new NodeMatchesTag(tag)));
}
@Override
public Map<String, ? extends Size> getSizes() {
return sizes.get(); return sizes.get();
} }
@Override @Override
public Set<? extends Image> listImages() { public Map<String, ? extends Image> getImages() {
return images.get(); return images.get();
} }
@Override @Override
public TemplateBuilder templateBuilder() { public TemplateBuilder templateBuilder() {
return this.templateBuilderProvider.get(); return templateBuilderProvider.get();
} }
} }

View File

@ -18,6 +18,7 @@
*/ */
package org.jclouds.rimuhosting.miro.compute.config; package org.jclouds.rimuhosting.miro.compute.config;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
@ -33,6 +34,7 @@ import org.jclouds.Constants;
import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.domain.Architecture; import org.jclouds.compute.domain.Architecture;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.Size; import org.jclouds.compute.domain.Size;
@ -40,7 +42,9 @@ import org.jclouds.compute.domain.internal.ImageImpl;
import org.jclouds.compute.domain.internal.SizeImpl; import org.jclouds.compute.domain.internal.SizeImpl;
import org.jclouds.compute.internal.ComputeServiceContextImpl; import org.jclouds.compute.internal.ComputeServiceContextImpl;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.ResourceLocation; import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope;
import org.jclouds.domain.internal.LocationImpl;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.RestContext; import org.jclouds.rest.RestContext;
import org.jclouds.rimuhosting.miro.RimuHostingAsyncClient; import org.jclouds.rimuhosting.miro.RimuHostingAsyncClient;
@ -49,7 +53,10 @@ import org.jclouds.rimuhosting.miro.compute.RimuHostingComputeService;
import org.jclouds.rimuhosting.miro.config.RimuHostingContextModule; import org.jclouds.rimuhosting.miro.config.RimuHostingContextModule;
import org.jclouds.rimuhosting.miro.domain.PricingPlan; import org.jclouds.rimuhosting.miro.domain.PricingPlan;
import com.google.common.base.Function;
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.Sets; import com.google.common.collect.Sets;
import com.google.inject.Provides; import com.google.inject.Provides;
@ -77,25 +84,66 @@ public class RimuHostingComputeServiceContextModule extends RimuHostingContextMo
@Provides @Provides
@Singleton @Singleton
@ResourceLocation Location getDefaultLocation(Map<String, ? extends Location> locations) {
String getRegion() { return locations.get("DCDALLAS");
return "default";
} }
@Provides @Provides
@Singleton @Singleton
protected Set<? extends Size> provideSizes(RimuHostingClient sync, Set<? extends Image> images, Map<String, ? extends Location> getDefaultLocations(RimuHostingClient sync, LogHolder holder,
LogHolder holder, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userExecutor) throws InterruptedException, Function<ComputeMetadata, String> indexer) {
final Set<Location> locations = Sets.newHashSet();
holder.logger.debug(">> providing locations");
for (final PricingPlan from : sync.getPricingPlanList()) {
try {
locations.add(new LocationImpl(LocationScope.ZONE, from.getDataCenter().getId(), from
.getDataCenter().getName(), null, true));
} catch (NullPointerException e) {
holder.logger.warn("datacenter not present in " + from.getId());
}
}
holder.logger.debug("<< locations(%d)", locations.size());
return Maps.uniqueIndex(locations, new Function<Location, String>() {
@Override
public String apply(Location from) {
return from.getId();
}
});
}
@Provides
@Singleton
protected Function<ComputeMetadata, String> indexer() {
return new Function<ComputeMetadata, String>() {
@Override
public String apply(ComputeMetadata from) {
return from.getId();
}
};
}
@Provides
@Singleton
protected Map<String, ? extends Size> provideSizes(RimuHostingClient sync,
Map<String, ? extends Image> images, LogHolder holder,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService userExecutor,
Function<ComputeMetadata, String> indexer) throws InterruptedException,
TimeoutException, ExecutionException { TimeoutException, ExecutionException {
final Set<Size> sizes = Sets.newHashSet(); final Set<Size> sizes = Sets.newHashSet();
holder.logger.debug(">> providing sizes"); holder.logger.debug(">> providing sizes");
for (final PricingPlan from : sync.getPricingPlanList()) { for (final PricingPlan from : sync.getPricingPlanList()) {
sizes.add(new SizeImpl(from.getId(), from.getDiskSize(), from.getRam(), try {
from.getDiskSize(), ImmutableSet.<Architecture> of(Architecture.X86_32, sizes.add(new SizeImpl(from.getId(), from.getId(), from.getDataCenter().getId(), null,
ImmutableMap.<String, String> of(), from.getDiskSize(), from.getRam(), from
.getDiskSize(), ImmutableSet.<Architecture> of(Architecture.X86_32,
Architecture.X86_64))); Architecture.X86_64)));
} catch (NullPointerException e) {
holder.logger.warn("datacenter not present in " + from.getId());
}
} }
holder.logger.debug("<< sizes(%d)", sizes.size()); holder.logger.debug("<< sizes(%d)", sizes.size());
return sizes; return Maps.uniqueIndex(sizes, indexer);
} }
private static class LogHolder { private static class LogHolder {
@ -108,9 +156,9 @@ public class RimuHostingComputeServiceContextModule extends RimuHostingContextMo
@Provides @Provides
@Singleton @Singleton
protected Set<? extends Image> provideImages(final RimuHostingClient sync, protected Map<String, ? extends Image> provideImages(final RimuHostingClient sync,
@ResourceLocation String location, LogHolder holder) throws InterruptedException, LogHolder holder, Function<ComputeMetadata, String> indexer)
ExecutionException, TimeoutException { throws InterruptedException, ExecutionException, TimeoutException {
final Set<Image> images = Sets.newHashSet(); final Set<Image> images = Sets.newHashSet();
holder.logger.debug(">> providing images"); holder.logger.debug(">> providing images");
for (final org.jclouds.rimuhosting.miro.domain.Image from : sync.getImageList()) { for (final org.jclouds.rimuhosting.miro.domain.Image from : sync.getImageList()) {
@ -130,10 +178,11 @@ public class RimuHostingComputeServiceContextModule extends RimuHostingContextMo
holder.logger.debug("<< didn't match os(%s)", matcher.group(2)); holder.logger.debug("<< didn't match os(%s)", matcher.group(2));
} }
} }
images.add(new ImageImpl(from.getId(), from.getDescription(), version, os, osDescription,
location, arch)); images.add(new ImageImpl(from.getId(), from.getDescription(), null, null, ImmutableMap
.<String, String> of(), from.getDescription(), version, os, osDescription, arch));
} }
holder.logger.debug("<< images(%d)", images.size()); holder.logger.debug("<< images(%d)", images.size());
return images; return Maps.uniqueIndex(images, indexer);
} }
} }

View File

@ -18,10 +18,13 @@
*/ */
package org.jclouds.rimuhosting.miro.config; package org.jclouds.rimuhosting.miro.config;
import com.google.common.base.Predicate;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Provides; import com.google.inject.Provides;
import org.jclouds.concurrent.internal.SyncProxy; import org.jclouds.concurrent.internal.SyncProxy;
import org.jclouds.http.RequiresHttp; import org.jclouds.http.RequiresHttp;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.predicates.SocketOpen;
import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.RestClientFactory; import org.jclouds.rest.RestClientFactory;
import org.jclouds.rimuhosting.miro.RimuHosting; import org.jclouds.rimuhosting.miro.RimuHosting;
@ -33,7 +36,9 @@ import org.jclouds.rimuhosting.miro.reference.RimuHostingConstants;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.URI; import java.net.URI;
import java.util.concurrent.TimeUnit;
/** /**
* Configures the RimuHosting connection. * Configures the RimuHosting connection.
@ -44,6 +49,12 @@ import java.net.URI;
@ConfiguresRestClient @ConfiguresRestClient
public class RimuHostingRestClientModule extends AbstractModule { public class RimuHostingRestClientModule extends AbstractModule {
@Provides
@Singleton
protected Predicate<InetSocketAddress> socketTester(SocketOpen open) {
return new RetryablePredicate<InetSocketAddress>(open, 130, 1, TimeUnit.SECONDS);
}
@Override @Override
protected void configure() { protected void configure() {
bindErrorHandlers(); bindErrorHandlers();
@ -66,15 +77,16 @@ public class RimuHostingRestClientModule extends AbstractModule {
@Provides @Provides
@Singleton @Singleton
public RimuHostingClient provideClient(RimuHostingAsyncClient client) throws IllegalArgumentException, public RimuHostingClient provideClient(RimuHostingAsyncClient client)
SecurityException, NoSuchMethodException { throws IllegalArgumentException, SecurityException, NoSuchMethodException {
return SyncProxy.create(RimuHostingClient.class, client); return SyncProxy.create(RimuHostingClient.class, client);
} }
@Provides @Provides
@Singleton @Singleton
@RimuHosting @RimuHosting
protected URI provideURI(@Named(RimuHostingConstants.PROPERTY_RIMUHOSTING_ENDPOINT) String endpoint) { protected URI provideURI(
@Named(RimuHostingConstants.PROPERTY_RIMUHOSTING_ENDPOINT) String endpoint) {
return URI.create(endpoint); return URI.create(endpoint);
} }

View File

@ -36,7 +36,7 @@ public class RimuHostingComputeServiceLiveTest extends BaseComputeServiceLiveTes
@Override @Override
public void setServiceDefaults() { public void setServiceDefaults() {
service = "rimuhosting"; service = "rimuhosting";
nodeName = "rimuhosting.jclouds"; tag = "rimuhosting.jclouds";
} }
protected Template buildTemplate(TemplateBuilder templateBuilder) { protected Template buildTemplate(TemplateBuilder templateBuilder) {

View File

@ -2,28 +2,27 @@
<!-- <!--
Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com> Copyright (C) 2009 Cloud Conscious, LLC.
<info@cloudconscious.com>
==================================================================== ====================================================================
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0 Unless required by
applicable law or agreed to in writing, software distributed
Unless required by applicable law or agreed to in writing, software under the License is distributed on an "AS IS" BASIS, WITHOUT
distributed under the License is distributed on an "AS IS" BASIS, WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
See the License for the specific language governing permissions and and limitations under the License.
limitations under the License.
==================================================================== ====================================================================
--> -->
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<!-- <!--
For more configuration infromation and examples see the Apache Log4j For more configuration infromation and examples see the Apache
website: http://logging.apache.org/log4j/ Log4j website: http://logging.apache.org/log4j/
--> -->
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
debug="false"> debug="false">
@ -39,13 +38,17 @@
<param name="Threshold" value="TRACE" /> <param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout"> <layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message${symbol_escape}n --> <!--
The default pattern: Date Priority [Category]
Message${symbol_escape}n
-->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" /> <param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!-- <!--
The full pattern: Date MS Priority [Category] (Thread:NDC) Message${symbol_escape}n The full pattern: Date MS Priority [Category]
<param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x) (Thread:NDC) Message${symbol_escape}n <param
%m%n"/> name="ConversionPattern" value="%d %-5r %-5p [%c]
(%t:%x) %m%n"/>
--> -->
</layout> </layout>
</appender> </appender>
@ -61,17 +64,45 @@
<param name="Threshold" value="TRACE" /> <param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout"> <layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message${symbol_escape}n --> <!--
The default pattern: Date Priority [Category]
Message${symbol_escape}n
-->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" /> <param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!-- <!--
The full pattern: Date MS Priority [Category] (Thread:NDC) Message${symbol_escape}n The full pattern: Date MS Priority [Category]
<param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x) (Thread:NDC) Message${symbol_escape}n <param
%m%n"/> name="ConversionPattern" value="%d %-5r %-5p [%c]
(%t:%x) %m%n"/>
-->
</layout>
</appender>
<!-- A time/date based rolling appender -->
<appender name="COMPUTEFILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds-compute.log" />
<param name="Append" value="true" />
<!-- Rollover at midnight each day -->
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category]
(Thread:NDC) Message\n <param name="ConversionPattern"
value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
--> -->
</layout> </layout>
</appender> </appender>
<appender name="ASYNCCOMPUTE" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="COMPUTEFILE" />
</appender>
<appender name="ASYNC" class="org.apache.log4j.AsyncAppender"> <appender name="ASYNC" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="FILE" /> <appender-ref ref="FILE" />
</appender> </appender>
@ -99,6 +130,11 @@
<appender-ref ref="ASYNCWIRE" /> <appender-ref ref="ASYNCWIRE" />
</category> </category>
<category name="jclouds.compute">
<priority value="TRACE" />
<appender-ref ref="ASYNCCOMPUTE" />
</category>
<!-- ======================= --> <!-- ======================= -->
<!-- Setup the Root category --> <!-- Setup the Root category -->
<!-- ======================= --> <!-- ======================= -->

View File

@ -2,4 +2,4 @@ service=ec2
driver=aws driver=aws
account=accesskeyid account=accesskeyid
key=secretaccesskey key=secretaccesskey
nodename=we_create_and_delete_based_on_key_and_security_group_name_not_instance_id nodetag=we_create_and_delete_based_on_key_and_security_group_name_not_instance_id

View File

@ -2,4 +2,4 @@ service=hostingdotcom
driver=hostingdotcom driver=hostingdotcom
account=user@youregistered.com account=user@youregistered.com
key=password key=password
nodename=name_of_your_vapp nodetag=name_of_your_vapp

View File

@ -2,4 +2,4 @@ service=cloudservers
driver=rackspace driver=rackspace
account=user account=user
key=your_key key=your_key
nodename=name_of_your_server nodetag=name_of_your_server

View File

@ -2,4 +2,4 @@ service=rimuhosting
driver=rimuhosting driver=rimuhosting
account=apikey account=apikey
key=apikey key=apikey
nodename=name_of_your_server nodetag=name_of_your_server

View File

@ -2,4 +2,4 @@ service=terremark
driver=terremark driver=terremark
account=user@youregistered.com account=user@youregistered.com
key=password key=password
nodename=name_of_your_vapp nodetag=name_of_your_vapp

View File

@ -4,4 +4,4 @@ driver=vcloud
vcloud.endpoint=https://vcloud_host_you_want/api vcloud.endpoint=https://vcloud_host_you_want/api
account=user@youregistered.com account=user@youregistered.com
key=password key=password
nodename=name_of_your_vapp nodetag=name_of_your_vapp

View File

@ -71,26 +71,26 @@
<input message="What is your account on ${service}?" addproperty="account"/> <input message="What is your account on ${service}?" addproperty="account"/>
<input message="What is the key for ${account}?" addproperty="key"/> <input message="What is the key for ${account}?" addproperty="key"/>
<input message="What is the nodename for the deployment?" addproperty="nodename"/> <input message="What is the nodetag for the deployment?" addproperty="nodetag"/>
<property name="url" value="compute://${account}:${key}@${service}"/> <property name="url" value="compute://${account}:${key}@${service}"/>
<target name="destroy" description="destroy the node ${nodename}"> <target name="destroy" description="destroy the nodes ${nodetag}">
<compute action="destroy" provider="${url}"> <compute actions="destroy" provider="${url}">
<node name="${nodename}" /> <nodes tag="${nodetag}" />
</compute> </compute>
<sleep seconds="5" /> <sleep seconds="5" />
</target> </target>
<target name="create" description="create the node ${nodename}" depends="destroy" > <target name="create" description="create the nodes ${nodetag}" >
<compute action="create" provider="${url}"> <compute actions="destroy,create" provider="${url}">
<node name="${nodename}" os="UBUNTU" size="SMALLEST" <nodes tag="${nodetag}" os="UBUNTU" size="SMALLEST"
runscript="runscript.sh" openports="22,${listenport}" runscript="runscript.sh" openports="22,${listenport}"
hostproperty="host" usernameproperty="username" passwordproperty="password" /> hostproperty="host" usernameproperty="username" passwordproperty="password" />
</compute> </compute>
</target> </target>
<target name="cargooverssh" depends="create" description="run cargo on remote node" > <target name="cargooverssh" depends="create" description="run cargo on remote nodes" >
<echo message="deploying tomcat and blaze to: ${nodename}" /> <echo message="deploying tomcat and blaze to: ${nodetag}" />
<cargo containerId="tomcat6x" output="build/output.log" log="build/cargo.log" action="start" timeout="600000"> <cargo containerId="tomcat6x" output="build/output.log" log="build/cargo.log" action="start" timeout="600000">
<zipurlinstaller installurl="${container.zip}" /> <zipurlinstaller installurl="${container.zip}" />
<configuration home="build/cargo" type="standalone"> <configuration home="build/cargo" type="standalone">

View File

@ -2,4 +2,4 @@ service=ec2
driver=aws driver=aws
account=accesskeyid account=accesskeyid
key=secretaccesskey key=secretaccesskey
nodename=we_create_and_delete_based_on_key_and_security_group_name_not_instance_id nodetag=we_create_and_delete_based_on_key_and_security_group_name_not_instance_id

View File

@ -2,4 +2,4 @@ service=hostingdotcom
driver=hostingdotcom driver=hostingdotcom
account=user@youregistered.com account=user@youregistered.com
key=password key=password
nodename=name_of_your_vapp nodetag=name_of_your_vapp

View File

@ -2,4 +2,4 @@ service=cloudservers
driver=rackspace driver=rackspace
account=user account=user
key=your_key key=your_key
nodename=name_of_your_server nodetag=name_of_your_server

View File

@ -2,4 +2,4 @@ service=rimuhosting
driver=rimuhosting driver=rimuhosting
account=apikey account=apikey
key=apikey key=apikey
nodename=name_of_your_server nodetag=name_of_your_server

View File

@ -2,4 +2,4 @@ service=terremark
driver=terremark driver=terremark
account=user@youregistered.com account=user@youregistered.com
key=password key=password
nodename=name_of_your_vapp nodetag=name_of_your_vapp

View File

@ -4,4 +4,4 @@ driver=vcloud
vcloud.endpoint=https://vcloud_host_you_want/api vcloud.endpoint=https://vcloud_host_you_want/api
account=user@youregistered.com account=user@youregistered.com
key=password key=password
nodename=name_of_your_vapp nodetag=name_of_your_vapp

View File

@ -65,56 +65,64 @@
<property name="jclouds.compute.url" value="compute://${account}:${key}@${service}" /> <property name="jclouds.compute.url" value="compute://${account}:${key}@${service}" />
<target name="list" description="list the identity of all nodes"> <target name="list" description="list the identity of all nodes">
<compute action="list" provider="${jclouds.compute.url}" /> <compute actions="list" provider="${jclouds.compute.url}" />
</target> </target>
<target name="list-details" description="list the details of all nodes"> <target name="list-details" description="list the details of all nodes">
<compute action="list-details" provider="${jclouds.compute.url}" /> <compute actions="list-details" provider="${jclouds.compute.url}" />
</target> </target>
<target name="list-images" description="list the images supported"> <target name="list-images" description="list the images supported">
<compute action="list-images" provider="${jclouds.compute.url}" /> <compute actions="list-images" provider="${jclouds.compute.url}" />
</target> </target>
<target name="list-sizes" description="list the sizes supported"> <target name="list-sizes" description="list the sizes supported">
<compute action="list-sizes" provider="${jclouds.compute.url}" /> <compute actions="list-sizes" provider="${jclouds.compute.url}" />
</target> </target>
<target name="destroy" description="destroy the node ${nodename}"> <target name="list-locations" description="list the locations supported">
<compute actions="list-locations" provider="${jclouds.compute.url}" />
</target>
<target name="dump" description="list all information we can obtain about the cloud">
<compute actions="list-locations,list-sizes,list-images,list-details" provider="${jclouds.compute.url}" />
</target>
<target name="destroy" description="destroy the node ${nodetag}">
<input <input
message="Which node do you wish to destroy" message="Which node do you wish to destroy"
addproperty="nodename" addproperty="nodetag"
/> />
<compute action="destroy" provider="${jclouds.compute.url}"> <compute actions="destroy" provider="${jclouds.compute.url}">
<node name="${nodename}" /> <node tag="${nodetag}" />
</compute> </compute>
</target> </target>
<target name="get" description="get the node ${nodename}"> <target name="get" description="get the node ${nodetag}">
<input <input
message="Which node do you wish to describe?" message="Which node do you wish to describe?"
addproperty="nodename" addproperty="nodetag"
/> />
<compute action="get" provider="${jclouds.compute.url}"> <compute actions="get" provider="${jclouds.compute.url}">
<node name="${nodename}" /> <node tag="${nodetag}" />
</compute> </compute>
</target> </target>
<property name="location" value="" /> <property name="location" value="" />
<target name="create" description="create the node ${nodename}"> <target name="create" description="create the node ${nodetag}">
<property name="os" value="UBUNTU" /> <property name="os" value="UBUNTU" />
<input <input
message="What do you want to name your node?" message="What do you want to name your node?"
addproperty="nodename" addproperty="nodetag"
/> />
<compute action="create" provider="${jclouds.compute.url}"> <compute actions="create" provider="${jclouds.compute.url}">
<node name="${nodename}" location="${location}" os="${os}" size="SMALLEST" hostproperty="host" usernameproperty="username" passwordproperty="password" /> <node tag="${nodetag}" location="${location}" os="${os}" size="SMALLEST" hostproperty="host" usernameproperty="username" passwordproperty="password" />
</compute> </compute>
</target> </target>

View File

@ -18,11 +18,9 @@
*/ */
package org.jclouds.tools.ant.taskdefs.compute; package org.jclouds.tools.ant.taskdefs.compute;
import static org.jclouds.compute.util.ComputeUtils.filterByName;
import static org.jclouds.compute.util.ComputeUtils.isKeyAuth; import static org.jclouds.compute.util.ComputeUtils.isKeyAuth;
import static org.jclouds.tools.ant.taskdefs.compute.ComputeTaskUtils.buildComputeMap; import static org.jclouds.tools.ant.taskdefs.compute.ComputeTaskUtils.buildComputeMap;
import static org.jclouds.tools.ant.taskdefs.compute.ComputeTaskUtils.createTemplateFromElement; import static org.jclouds.tools.ant.taskdefs.compute.ComputeTaskUtils.createTemplateFromElement;
import static org.jclouds.tools.ant.taskdefs.compute.ComputeTaskUtils.getNodeOptionsFromElement;
import static org.jclouds.tools.ant.taskdefs.compute.ComputeTaskUtils.ipOrEmptyString; import static org.jclouds.tools.ant.taskdefs.compute.ComputeTaskUtils.ipOrEmptyString;
import java.io.File; import java.io.File;
@ -39,15 +37,16 @@ import org.apache.tools.ant.Task;
import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.CreateNodeResponse;
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.Size; import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.options.RunNodeOptions; import org.jclouds.domain.Location;
import org.jclouds.http.HttpUtils; import org.jclouds.http.HttpUtils;
import com.google.common.base.CaseFormat; import com.google.common.base.CaseFormat;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.google.common.io.Files; import com.google.common.io.Files;
import com.google.inject.Provider; import com.google.inject.Provider;
@ -59,7 +58,7 @@ public class ComputeTask extends Task {
private final Map<URI, ComputeServiceContext> computeMap; private final Map<URI, ComputeServiceContext> computeMap;
private String provider; private String provider;
private String action; private String actions;
private NodeElement nodeElement; private NodeElement nodeElement;
/** /**
@ -82,7 +81,7 @@ public class ComputeTask extends Task {
} }
public static enum Action { public static enum Action {
CREATE, GET, LIST, LIST_DETAILS, DESTROY, LIST_IMAGES, LIST_SIZES CREATE, GET, LIST, LIST_DETAILS, DESTROY, LIST_IMAGES, LIST_SIZES, LIST_LOCATIONS
} }
/** /**
@ -90,10 +89,13 @@ public class ComputeTask extends Task {
*/ */
public void execute() throws BuildException { public void execute() throws BuildException {
ComputeServiceContext context = computeMap.get(HttpUtils.createUri(provider)); ComputeServiceContext context = computeMap.get(HttpUtils.createUri(provider));
Action action = Action.valueOf(CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE,
this.action));
try { try {
invokeActionOnService(action, context.getComputeService()); for (String action : Splitter.on(',').split(actions)) {
Action act = Action.valueOf(CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE,
action));
invokeActionOnService(act, context.getComputeService());
}
} finally { } finally {
context.close(); context.close();
} }
@ -132,6 +134,9 @@ public class ComputeTask extends Task {
case LIST_SIZES: case LIST_SIZES:
listSizes(computeService); listSizes(computeService);
break; break;
case LIST_LOCATIONS:
listLocations(computeService);
break;
default: default:
this.log("bad action: " + action, Project.MSG_ERR); this.log("bad action: " + action, Project.MSG_ERR);
} }
@ -139,7 +144,7 @@ public class ComputeTask extends Task {
private void listDetails(ComputeService computeService) { private void listDetails(ComputeService computeService) {
log("list details"); log("list details");
for (ComputeMetadata node : computeService.listNodes()) {// TODO for (ComputeMetadata node : computeService.getNodes().values()) {// TODO
// parallel // parallel
logDetails(computeService, node); logDetails(computeService, node);
} }
@ -147,58 +152,67 @@ public class ComputeTask extends Task {
private void listImages(ComputeService computeService) { private void listImages(ComputeService computeService) {
log("list images"); log("list images");
for (Image image : computeService.listImages()) {// TODO for (Image image : computeService.getImages().values()) {// TODO
log(String.format(" image location=%s, id=%s, version=%s, arch=%s, osfam=%s, desc=%s", log(String.format(" image location=%s, id=%s, version=%s, arch=%s, osfam=%s, desc=%s",
image.getLocation(), image.getId(), image.getVersion(), image.getArchitecture(), image.getLocationId(), image.getId(), image.getVersion(),
image.getOsFamily(), image.getOsDescription())); image.getArchitecture(), image.getOsFamily(), image.getOsDescription()));
} }
} }
private void listSizes(ComputeService computeService) { private void listSizes(ComputeService computeService) {
log("list sizes"); log("list sizes");
for (Size size : computeService.listSizes()) {// TODO for (Size size : computeService.getSizes().values()) {// TODO
log(String.format(" size id=%s, cores=%s, ram=%s, disk=%s", size.getId(), size log(String.format(" size id=%s, cores=%s, ram=%s, disk=%s", size.getId(), size
.getCores(), size.getRam(), size.getDisk())); .getCores(), size.getRam(), size.getDisk()));
} }
} }
private void listLocations(ComputeService computeService) {
log("list locations");
for (Location location : computeService.getLocations().values()) {// TODO
log(String.format(" location id=%s, scope=%s, description=%s, parent=%s, assignable=%s",
location.getId(), location.getScope(), location.getDescription(), location
.getParent(), location.isAssignable()));
}
}
private void list(ComputeService computeService) { private void list(ComputeService computeService) {
log("list"); log("list");
for (ComputeMetadata node : computeService.listNodes()) { for (ComputeMetadata node : computeService.getNodes().values()) {
log(String.format(" location=%s, id=%s, name=%s", node.getLocation(), node.getId(), node log(String.format(" location=%s, id=%s, tag=%s", node.getLocationId(), node.getId(),
.getName())); node.getName()));
} }
} }
private void create(ComputeService computeService) { private void create(ComputeService computeService) {
String name = nodeElement.getName(); String tag = nodeElement.getTag();
log(String.format("create name: %s, size: %s, os: %s", name, nodeElement.getSize(), log(String.format("create tag: %s, count: %d, size: %s, os: %s", tag, nodeElement.getCount(),
nodeElement.getOs())); nodeElement.getSize(), nodeElement.getOs()));
Template template = createTemplateFromElement(nodeElement, computeService); Template template = createTemplateFromElement(nodeElement, computeService);
RunNodeOptions options = getNodeOptionsFromElement(nodeElement); NodeMetadata createdNode = Iterables.getOnlyElement(computeService.runNodes(tag, nodeElement
.getCount(), template));
CreateNodeResponse createdNode = computeService.runNode(name, template, options);
logNodeDetails(createdNode); logNodeDetails(createdNode);
addNodeDetailsAsProjectProperties(createdNode); addNodeDetailsAsProjectProperties(createdNode);
} }
private void logNodeDetails(CreateNodeResponse createdNode) { private void logNodeDetails(NodeMetadata createdNode) {
log(String.format(" id=%s, name=%s, connection=%s:%s@%s", createdNode.getId(), createdNode log(String.format(" id=%s, tag=%s, location=%s, tag=%s, connection=%s:%s@%s", createdNode
.getName(), createdNode.getCredentials().account, createdNode.getCredentials().key, .getId(), createdNode.getTag(), createdNode.getLocationId(), createdNode.getName(),
createdNode.getPublicAddresses().first().getHostAddress())); createdNode.getCredentials().account, createdNode.getCredentials().key,
ipOrEmptyString(createdNode.getPublicAddresses())));
} }
private void addNodeDetailsAsProjectProperties(CreateNodeResponse createdNode) { private void addNodeDetailsAsProjectProperties(NodeMetadata createdNode) {
if (nodeElement.getIdproperty() != null) if (nodeElement.getIdproperty() != null)
getProject().setProperty(nodeElement.getIdproperty(), createdNode.getId()); getProject().setProperty(nodeElement.getIdproperty(), createdNode.getId());
if (nodeElement.getHostproperty() != null) if (nodeElement.getHostproperty() != null)
getProject().setProperty(nodeElement.getHostproperty(), getProject().setProperty(nodeElement.getHostproperty(),
createdNode.getPublicAddresses().first().getHostAddress()); ipOrEmptyString(createdNode.getPublicAddresses()));
if (nodeElement.getKeyfile() != null && isKeyAuth(createdNode)) if (nodeElement.getKeyfile() != null && isKeyAuth(createdNode))
try { try {
Files.write(createdNode.getCredentials().key, new File(nodeElement.getKeyfile()), Files.write(createdNode.getCredentials().key, new File(nodeElement.getKeyfile()),
@ -215,54 +229,49 @@ public class ComputeTask extends Task {
} }
private void destroy(ComputeService computeService) { private void destroy(ComputeService computeService) {
log(String.format("destroy name: %s", nodeElement.getName())); log(String.format("destroy tag: %s", nodeElement.getTag()));
Iterable<? extends ComputeMetadata> nodesThatMatch = filterByName(computeService.listNodes(), computeService.destroyNodes(nodeElement.getTag());
nodeElement.getName());
for (ComputeMetadata node : nodesThatMatch) {
log(String.format(" destroying id=%s, name=%s", node.getId(), node.getName()));
computeService.destroyNode(node);
}
} }
private void get(ComputeService computeService) { private void get(ComputeService computeService) {
log(String.format("get name: %s", nodeElement.getName())); log(String.format("get tag: %s", nodeElement.getTag()));
Iterable<? extends ComputeMetadata> nodesThatMatch = filterByName(computeService.listNodes(), for (ComputeMetadata node : computeService.getNodes(nodeElement.getTag())) {
nodeElement.getName());
for (ComputeMetadata node : nodesThatMatch) {
logDetails(computeService, node); logDetails(computeService, node);
} }
} }
private void logDetails(ComputeService computeService, ComputeMetadata node) { private void logDetails(ComputeService computeService, ComputeMetadata node) {
NodeMetadata metadata = computeService.getNodeMetadata(node); NodeMetadata metadata = node instanceof NodeMetadata ? NodeMetadata.class.cast(node)
: computeService.getNodeMetadata(node);
log(String log(String
.format( .format(
" node id=%s, name=%s, location=%s, state=%s, publicIp=%s, privateIp=%s, extra=%s", " node id=%s, name=%s, tag=%s, location=%s, state=%s, publicIp=%s, privateIp=%s, extra=%s",
metadata.getId(), node.getName(), node.getLocation(), metadata.getState(), metadata.getId(), metadata.getName(), metadata.getTag(), metadata
ipOrEmptyString(metadata.getPublicAddresses()), ipOrEmptyString(metadata .getLocationId(), metadata.getState(), ComputeTaskUtils
.getPrivateAddresses()), metadata.getExtra())); .ipOrEmptyString(metadata.getPublicAddresses()),
ipOrEmptyString(metadata.getPrivateAddresses()), metadata.getExtra()));
} }
/** /**
* @return the configured {@link NodeElement} element * @return the configured {@link NodeElement} element
*/ */
public final NodeElement createNode() { public final NodeElement createNodes() {
if (getNode() == null) { if (getNodes() == null) {
this.nodeElement = new NodeElement(); this.nodeElement = new NodeElement();
} }
return this.nodeElement; return this.nodeElement;
} }
public NodeElement getNode() { public NodeElement getNodes() {
return this.nodeElement; return this.nodeElement;
} }
public String getAction() { public String getActions() {
return action; return actions;
} }
public void setAction(String action) { public void setActions(String actions) {
this.action = action; this.actions = actions;
} }
public NodeElement getNodeElement() { public NodeElement getNodeElement() {

View File

@ -31,24 +31,22 @@ import java.net.URI;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Properties; import java.util.Properties;
import java.util.SortedSet; import java.util.Set;
import org.apache.tools.ant.BuildException; import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project; import org.apache.tools.ant.Project;
import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.ComputeServiceContextFactory; import org.jclouds.compute.ComputeServiceContextFactory;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.options.RunNodeOptions; import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.ssh.jsch.config.JschSshClientModule; import org.jclouds.ssh.jsch.config.JschSshClientModule;
import org.jclouds.tools.ant.logging.config.AntLoggingModule; import org.jclouds.tools.ant.logging.config.AntLoggingModule;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
@ -99,20 +97,11 @@ public class ComputeTaskUtils {
static Template createTemplateFromElement(NodeElement nodeElement, ComputeService computeService) { static Template createTemplateFromElement(NodeElement nodeElement, ComputeService computeService) {
TemplateBuilder templateBuilder = computeService.templateBuilder(); TemplateBuilder templateBuilder = computeService.templateBuilder();
if (nodeElement.getLocation() != null && !"".equals(nodeElement.getLocation())) if (nodeElement.getLocation() != null && !"".equals(nodeElement.getLocation()))
templateBuilder.location(nodeElement.getLocation()); templateBuilder.locationId(nodeElement.getLocation());
if (nodeElement.getImage() != null && !"".equals(nodeElement.getImage())) { if (nodeElement.getImage() != null && !"".equals(nodeElement.getImage())) {
final String imageId = nodeElement.getImage(); final String imageId = nodeElement.getImage();
try { try {
Image image = Iterables.getOnlyElement(Iterables.filter(computeService.listImages(), templateBuilder.imageId(imageId);
new Predicate<Image>() {
@Override
public boolean apply(Image input) {
return input.getId().equals(imageId);
}
}));
templateBuilder.fromImage(image);
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
throw new BuildException("image not found " + nodeElement.getImage()); throw new BuildException("image not found " + nodeElement.getImage());
} }
@ -120,6 +109,8 @@ public class ComputeTaskUtils {
templateBuilder.osFamily(OsFamily.valueOf(nodeElement.getOs())); templateBuilder.osFamily(OsFamily.valueOf(nodeElement.getOs()));
} }
addSizeFromElementToTemplate(nodeElement, templateBuilder); addSizeFromElementToTemplate(nodeElement, templateBuilder);
templateBuilder.options(getNodeOptionsFromElement(nodeElement));
return templateBuilder.build(); return templateBuilder.build();
} }
@ -136,15 +127,15 @@ public class ComputeTaskUtils {
} }
} }
static RunNodeOptions getNodeOptionsFromElement(NodeElement nodeElement) { static TemplateOptions getNodeOptionsFromElement(NodeElement nodeElement) {
RunNodeOptions options = new RunNodeOptions() TemplateOptions options = new TemplateOptions()
.openPorts(getPortsToOpenFromElement(nodeElement)); .inboundPorts(getPortsToOpenFromElement(nodeElement));
addRunScriptToOptionsIfPresentInNodeElement(nodeElement, options); addRunScriptToOptionsIfPresentInNodeElement(nodeElement, options);
return options; return options;
} }
static void addRunScriptToOptionsIfPresentInNodeElement(NodeElement nodeElement, static void addRunScriptToOptionsIfPresentInNodeElement(NodeElement nodeElement,
RunNodeOptions options) { TemplateOptions options) {
if (nodeElement.getRunscript() != null) if (nodeElement.getRunscript() != null)
try { try {
options.runScript(Files.toByteArray(nodeElement.getRunscript())); options.runScript(Files.toByteArray(nodeElement.getRunscript()));
@ -153,9 +144,9 @@ public class ComputeTaskUtils {
} }
} }
static String ipOrEmptyString(SortedSet<InetAddress> set) { static String ipOrEmptyString(Set<InetAddress> set) {
if (set.size() > 0) { if (set.size() > 0) {
return set.last().getHostAddress(); return Iterables.get(set, 0).getHostAddress();
} else { } else {
return ""; return "";
} }

View File

@ -25,10 +25,11 @@ import java.io.File;
* @author Ivan Meredith * @author Ivan Meredith
*/ */
public class NodeElement { public class NodeElement {
private String name; private String tag;
private String size; private String size;
private String os; private String os;
private String image; private String image;
private int count = 1;
private String openports = "22"; private String openports = "22";
private String passwordproperty; private String passwordproperty;
private String keyfile; private String keyfile;
@ -46,14 +47,6 @@ public class NodeElement {
this.location = location; this.location = location;
} }
String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
String getUsernameproperty() { String getUsernameproperty() {
return usernameproperty; return usernameproperty;
} }
@ -153,4 +146,20 @@ public class NodeElement {
return image; return image;
} }
public void setCount(int count) {
this.count = count;
}
public int getCount() {
return count;
}
public void setTag(String tag) {
this.tag = tag;
}
public String getTag() {
return tag;
}
} }

View File

@ -21,33 +21,39 @@ package org.jclouds.vcloud.compute;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; 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 org.jclouds.compute.util.ComputeUtils.METADATA_TO_ID;
import static org.jclouds.concurrent.ConcurrentUtils.awaitCompletion;
import static org.jclouds.concurrent.ConcurrentUtils.makeListenable;
import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.processorCount; import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.processorCount;
import java.net.InetAddress; import java.net.InetAddress;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Provider; import javax.inject.Provider;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeService;
import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.ComputeType; import org.jclouds.compute.domain.ComputeType;
import org.jclouds.compute.domain.CreateNodeResponse;
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.NodeSet;
import org.jclouds.compute.domain.NodeState; import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.Size; import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.domain.internal.CreateNodeResponseImpl;
import org.jclouds.compute.domain.internal.NodeMetadataImpl; import org.jclouds.compute.domain.internal.NodeMetadataImpl;
import org.jclouds.compute.options.RunNodeOptions; import org.jclouds.compute.domain.internal.NodeSetImpl;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.util.ComputeUtils; import org.jclouds.compute.util.ComputeUtils;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.VCloudClient;
import org.jclouds.vcloud.VCloudMediaType; import org.jclouds.vcloud.VCloudMediaType;
@ -57,11 +63,14 @@ import org.jclouds.vcloud.domain.VApp;
import org.jclouds.vcloud.domain.VAppStatus; import org.jclouds.vcloud.domain.VAppStatus;
import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions; import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions;
import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
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.Iterables;
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.common.util.concurrent.ListenableFuture;
import com.google.inject.Inject; import com.google.inject.Inject;
/** /**
@ -69,16 +78,33 @@ import com.google.inject.Inject;
*/ */
@Singleton @Singleton
public class VCloudComputeService implements ComputeService, VCloudComputeClient { public class VCloudComputeService implements ComputeService, VCloudComputeClient {
private static class NodeMatchesTag implements Predicate<NodeMetadata> {
private final String tag;
@Override
public boolean apply(NodeMetadata from) {
return from.getTag().equals(tag);
}
public NodeMatchesTag(String tag) {
super();
this.tag = tag;
}
};
@Resource @Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER) @Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
private final VCloudClient client; private final VCloudClient client;
protected final Provider<Set<? extends Image>> images; protected final Provider<Map<String, ? extends Image>> images;
protected final Provider<Set<? extends Size>> sizes; protected final Provider<Map<String, ? extends Size>> sizes;
protected final Provider<Map<String, ? extends Location>> locations;
protected final Provider<TemplateBuilder> templateBuilderProvider; protected final Provider<TemplateBuilder> templateBuilderProvider;
protected final ComputeUtils utils; protected final ComputeUtils utils;
protected final Predicate<String> taskTester; protected final Predicate<String> taskTester;
protected final Predicate<VApp> notFoundTester; protected final Predicate<VApp> notFoundTester;
protected final ExecutorService executor;
protected static final Map<VAppStatus, NodeState> vAppStatusToNodeState = ImmutableMap protected static final Map<VAppStatus, NodeState> vAppStatusToNodeState = ImmutableMap
.<VAppStatus, NodeState> builder().put(VAppStatus.OFF, NodeState.TERMINATED).put( .<VAppStatus, NodeState> builder().put(VAppStatus.OFF, NodeState.TERMINATED).put(
@ -89,65 +115,92 @@ public class VCloudComputeService implements ComputeService, VCloudComputeClient
@Inject @Inject
public VCloudComputeService(VCloudClient client, public VCloudComputeService(VCloudClient client,
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateBuilder> templateBuilderProvider,
Provider<Set<? extends Image>> images, Provider<Set<? extends Size>> sizes, Provider<Map<String, ? extends Image>> images,
ComputeUtils utils, Predicate<String> successTester, Provider<Map<String, ? extends Size>> sizes,
@Named("NOT_FOUND") Predicate<VApp> notFoundTester) { Provider<Map<String, ? extends Location>> locations, ComputeUtils utils,
Predicate<String> successTester, @Named("NOT_FOUND") Predicate<VApp> notFoundTester,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
this.taskTester = successTester; this.taskTester = successTester;
this.client = client; this.client = client;
this.images = images; this.images = images;
this.sizes = sizes; this.sizes = sizes;
this.locations = locations;
this.templateBuilderProvider = templateBuilderProvider; this.templateBuilderProvider = templateBuilderProvider;
this.utils = utils; this.utils = utils;
this.notFoundTester = notFoundTester; this.notFoundTester = notFoundTester;
this.executor = executor;
} }
@Override @Override
public CreateNodeResponse runNode(String name, Template template) { public NodeSet runNodes(final String tag, int max, final Template template) {
return this.runNode(name, template, RunNodeOptions.NONE); checkArgument(tag.indexOf('-') == -1, "tag cannot contain hyphens");
checkNotNull(template.getLocation(), "location");
// TODO: find next id
final Set<NodeMetadata> nodes = Sets.newHashSet();
Set<ListenableFuture<Void>> responses = Sets.newHashSet();
for (int i = 0; i < max; i++) {
final String name = String.format("%s-%d", tag, i + 1);
responses.add(makeListenable(executor.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
runVAppAndAddToSet(name, tag, template, nodes);
return null;
}
}), executor));
}
awaitCompletion(responses, executor, null, logger, "nodes");
return new NodeSetImpl(nodes);
} }
@Override private void runVAppAndAddToSet(String name, String tag, Template template,
public CreateNodeResponse runNode(String name, Template template, RunNodeOptions options) { Set<NodeMetadata> nodes) {
checkNotNull(template.getImage().getLocation(), "location"); Map<String, String> metaMap = start(template.getLocation().getId(), name, template.getImage()
Map<String, String> metaMap = start(template.getImage().getLocation(), name, template .getId(), template.getSize().getCores(), template.getSize().getRam(), template
.getImage().getId(), template.getSize().getCores(), template.getSize().getRam(), .getSize().getDisk() * 1024 * 1024l, ImmutableMap.<String, String> of(), template
template.getSize().getDisk() * 1024 * 1024l, ImmutableMap.<String, String> of(), .getOptions().getInboundPorts());
options.getOpenPorts());
VApp vApp = client.getVApp(metaMap.get("id")); VApp vApp = client.getVApp(metaMap.get("id"));
CreateNodeResponse node = newCreateNodeResponse(template, metaMap, vApp); NodeMetadata node = newCreateNodeResponse(tag, template, metaMap, vApp);
if (options.getRunScript() != null) { nodes.add(node);
utils.runScriptOnNode(node, options.getRunScript()); if (template.getOptions().getRunScript() != null) {
utils.runScriptOnNode(node, template.getOptions().getRunScript());
} }
return node;
} }
protected CreateNodeResponse newCreateNodeResponse(Template template, protected NodeMetadata newCreateNodeResponse(String tag, Template template,
Map<String, String> metaMap, VApp vApp) { Map<String, String> metaMap, VApp vApp) {
return new CreateNodeResponseImpl(vApp.getId(), vApp.getName(), template.getImage() return new NodeMetadataImpl(vApp.getId(), vApp.getName(), template.getLocation().getId(),
.getLocation(), vApp.getLocation(), ImmutableMap.<String, String> of(), vApp.getLocation(), ImmutableMap.<String, String> of(), tag, vAppStatusToNodeState
vAppStatusToNodeState.get(vApp.getStatus()), getPublicAddresses(vApp.getId()), .get(vApp.getStatus()), getPublicAddresses(vApp.getId()),
getPrivateAddresses(vApp.getId()), new Credentials(metaMap.get("username"), metaMap getPrivateAddresses(vApp.getId()), ImmutableMap.<String, String> of(),
.get("password")), ImmutableMap.<String, String> of()); new Credentials(metaMap.get("username"), metaMap.get("password")));
} }
@Override @Override
public NodeMetadata getNodeMetadata(ComputeMetadata node) { public NodeMetadata getNodeMetadata(ComputeMetadata node) {
checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not " checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not "
+ node.getType()); + node.getType());
return getNodeMetadataByIdInVDC(checkNotNull(node.getLocation(), "location"), checkNotNull( return getNodeMetadataByIdInVDC(checkNotNull(node.getLocationId(), "location"), checkNotNull(
node.getId(), "node.id")); node.getId(), "node.id"));
} }
protected NodeMetadata getNodeMetadataByIdInVDC(String vDCId, String id) { protected NodeMetadata getNodeMetadataByIdInVDC(String vDCId, String id) {
VApp vApp = client.getVApp(id); VApp vApp = client.getVApp(id);
String tag = vApp.getName().replaceAll("-[0-9]+", "");
return new NodeMetadataImpl(vApp.getId(), vApp.getName(), vDCId, vApp.getLocation(), return new NodeMetadataImpl(vApp.getId(), vApp.getName(), vDCId, vApp.getLocation(),
ImmutableMap.<String, String> of(), vAppStatusToNodeState.get(vApp.getStatus()), ImmutableMap.<String, String> of(), tag,
vApp.getNetworkToAddresses().values(), ImmutableSet.<InetAddress> of(), ImmutableMap vAppStatusToNodeState.get(vApp.getStatus()), vApp.getNetworkToAddresses().values(),
.<String, String> of()); ImmutableSet.<InetAddress> of(), ImmutableMap.<String, String> of(), null);
} }
@Override @Override
public Set<ComputeMetadata> listNodes() { public Map<String, ? extends ComputeMetadata> getNodes() {
logger.debug(">> listing vApps");
Map<String, ? extends ComputeMetadata> nodes = doGetNodes();
logger.debug("<< list(%d)", nodes.size());
return nodes;
}
private Map<String, ? extends ComputeMetadata> doGetNodes() {
Set<ComputeMetadata> nodes = Sets.newHashSet(); Set<ComputeMetadata> nodes = Sets.newHashSet();
for (NamedResource vdc : client.getDefaultOrganization().getVDCs().values()) { for (NamedResource vdc : client.getDefaultOrganization().getVDCs().values()) {
for (NamedResource resource : client.getVDC(vdc.getId()).getResourceEntities().values()) { for (NamedResource resource : client.getVDC(vdc.getId()).getResourceEntities().values()) {
@ -156,7 +209,7 @@ public class VCloudComputeService implements ComputeService, VCloudComputeClient
} }
} }
} }
return nodes; return Maps.uniqueIndex(nodes, METADATA_TO_ID);
} }
@Override @Override
@ -172,12 +225,12 @@ public class VCloudComputeService implements ComputeService, VCloudComputeClient
} }
@Override @Override
public Set<? extends Size> listSizes() { public Map<String, ? extends Size> getSizes() {
return sizes.get(); return sizes.get();
} }
@Override @Override
public Set<? extends Image> listImages() { public Map<String, ? extends Image> getImages() {
return images.get(); return images.get();
} }
@ -300,4 +353,53 @@ public class VCloudComputeService implements ComputeService, VCloudComputeClient
return Sets.newHashSet(vApp.getNetworkToAddresses().values()); return Sets.newHashSet(vApp.getNetworkToAddresses().values());
} }
@Override
public void destroyNodes(String tag) { // TODO parallel
logger.debug(">> terminating servers by tag(%s)", tag);
Set<ListenableFuture<Void>> responses = Sets.newHashSet();
for (final NodeMetadata node : doGetNodes(tag)) {
responses.add(makeListenable(executor.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
destroyNode(node);
return null;
}
}), executor));
}
awaitCompletion(responses, executor, null, logger, "nodes");
logger.debug("<< destroyed");
}
@Override
public Map<String, ? extends Location> getLocations() {
return locations.get();
}
@Override
public NodeSet getNodes(String tag) {
logger.debug(">> listing servers by tag(%s)", tag);
NodeSet nodes = doGetNodes(tag);
logger.debug("<< list(%d)", nodes.size());
return nodes;
}
protected NodeSet doGetNodes(final String tag) {
Iterable<NodeMetadata> nodes = Iterables.filter(Iterables.transform(doGetNodes().values(),
new Function<ComputeMetadata, NodeMetadata>() {
@Override
public NodeMetadata apply(ComputeMetadata from) {
return getNodeMetadata(from);
}
}), new Predicate<NodeMetadata>() {
@Override
public boolean apply(NodeMetadata input) {
return tag.equals(input.getTag());
}
});
return new NodeSetImpl(Iterables.filter(nodes, new NodeMatchesTag(tag)));
}
} }

View File

@ -18,6 +18,7 @@
*/ */
package org.jclouds.vcloud.compute.config; package org.jclouds.vcloud.compute.config;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -32,6 +33,7 @@ import org.jclouds.Constants;
import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.domain.Architecture; import org.jclouds.compute.domain.Architecture;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.Size; import org.jclouds.compute.domain.Size;
@ -40,7 +42,9 @@ import org.jclouds.compute.domain.internal.SizeImpl;
import org.jclouds.compute.internal.ComputeServiceContextImpl; import org.jclouds.compute.internal.ComputeServiceContextImpl;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.concurrent.ConcurrentUtils; import org.jclouds.concurrent.ConcurrentUtils;
import org.jclouds.domain.ResourceLocation; import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope;
import org.jclouds.domain.internal.LocationImpl;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.RestContext; import org.jclouds.rest.RestContext;
import org.jclouds.vcloud.VCloudAsyncClient; import org.jclouds.vcloud.VCloudAsyncClient;
@ -53,8 +57,13 @@ import org.jclouds.vcloud.domain.Catalog;
import org.jclouds.vcloud.domain.CatalogItem; import org.jclouds.vcloud.domain.CatalogItem;
import org.jclouds.vcloud.domain.NamedResource; import org.jclouds.vcloud.domain.NamedResource;
import org.jclouds.vcloud.domain.VAppTemplate; import org.jclouds.vcloud.domain.VAppTemplate;
import org.jclouds.vcloud.domain.VDC;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.Injector; import com.google.inject.Injector;
@ -91,13 +100,6 @@ public class VCloudComputeServiceContextModule extends VCloudContextModule {
return new ComputeServiceContextImpl<VCloudAsyncClient, VCloudClient>(computeService, context); return new ComputeServiceContextImpl<VCloudAsyncClient, VCloudClient>(computeService, context);
} }
@Provides
@Singleton
@ResourceLocation
String getVDC(VCloudClient client) {
return client.getDefaultVDC().getId();
}
protected static class LogHolder { protected static class LogHolder {
@Resource @Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER) @Named(ComputeServiceConstants.COMPUTE_LOGGER)
@ -106,10 +108,12 @@ public class VCloudComputeServiceContextModule extends VCloudContextModule {
@Provides @Provides
@Singleton @Singleton
protected Set<? extends Image> provideImages(final VCloudClient client, protected Map<String, ? extends Image> provideImages(final VCloudClient client,
final @ResourceLocation String vDC, LogHolder holder, final Location vDC, LogHolder holder,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor,
throws InterruptedException, ExecutionException, TimeoutException { Function<ComputeMetadata, String> indexer) throws InterruptedException,
ExecutionException, TimeoutException {
// TODO multi-VDC
final Set<Image> images = Sets.newHashSet(); final Set<Image> images = Sets.newHashSet();
holder.logger.debug(">> providing images"); holder.logger.debug(">> providing images");
Catalog response = client.getDefaultCatalog(); Catalog response = client.getDefaultCatalog();
@ -132,8 +136,9 @@ public class VCloudComputeServiceContextModule extends VCloudContextModule {
Architecture arch = resource.getName().indexOf("64") == -1 ? Architecture.X86_32 Architecture arch = resource.getName().indexOf("64") == -1 ? Architecture.X86_32
: Architecture.X86_64; : Architecture.X86_64;
VAppTemplate template = client.getVAppTemplate(item.getEntity().getId()); VAppTemplate template = client.getVAppTemplate(item.getEntity().getId());
images.add(new ImageImpl(resource.getId(), template.getName(), "", myOs, images.add(new ImageImpl(resource.getId(), template.getName(), vDC.getId(),
template.getName(), vDC, arch)); template.getLocation(), ImmutableMap.<String, String> of(), template
.getDescription(), "", myOs, template.getName(), arch));
return null; return null;
} }
}), executor)); }), executor));
@ -142,21 +147,60 @@ public class VCloudComputeServiceContextModule extends VCloudContextModule {
} }
ConcurrentUtils.awaitCompletion(responses, executor, null, holder.logger, "images"); ConcurrentUtils.awaitCompletion(responses, executor, null, holder.logger, "images");
return images; return Maps.uniqueIndex(images, indexer);
} }
@Provides @Provides
@Singleton @Singleton
protected Set<? extends Size> provideSizes(VCloudClient client, Set<? extends Image> images, protected Function<ComputeMetadata, String> indexer() {
LogHolder holder, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) return new Function<ComputeMetadata, String>() {
@Override
public String apply(ComputeMetadata from) {
return from.getId();
}
};
}
@Provides
@Singleton
Map<String, ? extends Location> provideLocations(final VCloudClient client) {
return Maps.uniqueIndex(Iterables.transform(client.getDefaultOrganization().getVDCs()
.values(), new Function<NamedResource, Location>() {
@Override
public Location apply(NamedResource from) {
VDC vdc = client.getVDC(from.getId());
return new LocationImpl(LocationScope.ZONE, vdc.getId(), vdc.getName(), null, true);
}
}), new Function<Location, String>() {
@Override
public String apply(Location from) {
return from.getId();
}
});
}
@Provides
@Singleton
Location getVDC(VCloudClient client, Map<String, ? extends Location> locations) {
return locations.get(client.getDefaultVDC().getId());
}
@Provides
@Singleton
protected Map<String, ? extends Size> provideSizes(Function<ComputeMetadata, String> indexer,
VCloudClient client, Map<String, ? extends Image> images, LogHolder holder,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor)
throws InterruptedException, TimeoutException, ExecutionException { throws InterruptedException, TimeoutException, ExecutionException {
Set<Size> sizes = Sets.newHashSet(); Set<Size> sizes = Sets.newHashSet();
for (int cpus : new int[] { 1, 2, 4 }) for (int cpus : new int[] { 1, 2, 4 })
for (int ram : new int[] { 512, 1024, 2048, 4096, 8192, 16384 }) for (int ram : new int[] { 512, 1024, 2048, 4096, 8192, 16384 })
sizes.add(new SizeImpl(String.format("cpu=%d,ram=%s,disk=%d", cpus, ram, 10), cpus, sizes.add(new SizeImpl(String.format("cpu=%d,ram=%s,disk=%d", cpus, ram, 10), null,
ram, 10, ImmutableSet.<Architecture> of(Architecture.X86_32, null, null, ImmutableMap.<String, String> of(), cpus, ram, 10, ImmutableSet
Architecture.X86_64))); .<Architecture> of(Architecture.X86_32, Architecture.X86_64)));
return sizes; return Maps.uniqueIndex(sizes, indexer);
} }
} }

View File

@ -29,12 +29,12 @@ import static org.testng.Assert.assertNotNull;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URI; import java.net.URI;
import java.util.List; import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.PropertiesBuilder;
import org.jclouds.concurrent.config.ExecutorServiceModule; import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.encryption.EncryptionService; import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.RequiresHttp; import org.jclouds.http.RequiresHttp;
@ -139,7 +139,18 @@ public class VCloudLoginLiveTest {
context = new RestContextBuilder<VCloudLoginAsyncClient, VCloudLoginAsyncClient>( context = new RestContextBuilder<VCloudLoginAsyncClient, VCloudLoginAsyncClient>(
new TypeLiteral<VCloudLoginAsyncClient>() { new TypeLiteral<VCloudLoginAsyncClient>() {
}, new TypeLiteral<VCloudLoginAsyncClient>() { }, new TypeLiteral<VCloudLoginAsyncClient>() {
}, new Properties()) { }, new PropertiesBuilder() {
@Override
public PropertiesBuilder withCredentials(String account, String key) {
return null;
}
@Override
public PropertiesBuilder withEndpoint(URI endpoint) {
return null;
}
}.build()) {
public void addContextModule(List<Module> modules) { public void addContextModule(List<Module> modules) {

View File

@ -3,17 +3,19 @@ package org.jclouds.vcloud.hostingdotcom.compute;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.concurrent.ExecutorService;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Provider; import javax.inject.Provider;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.Size; import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.util.ComputeUtils; import org.jclouds.compute.util.ComputeUtils;
import org.jclouds.domain.Location;
import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.VCloudClient;
import org.jclouds.vcloud.compute.VCloudComputeService; import org.jclouds.vcloud.compute.VCloudComputeService;
import org.jclouds.vcloud.domain.VApp; import org.jclouds.vcloud.domain.VApp;
@ -29,12 +31,15 @@ import com.google.common.collect.ImmutableMap;
public class HostingDotComVCloudComputeService extends VCloudComputeService { public class HostingDotComVCloudComputeService extends VCloudComputeService {
@Inject @Inject
HostingDotComVCloudComputeService(VCloudClient client, public HostingDotComVCloudComputeService(VCloudClient client,
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateBuilder> templateBuilderProvider,
Provider<Set<? extends Image>> images, Provider<Set<? extends Size>> sizes, Provider<Map<String, ? extends Image>> images,
Predicate<String> successTester, ComputeUtils utils, Provider<Map<String, ? extends Size>> sizes,
@Named("NOT_FOUND") Predicate<VApp> notFoundTester) { Provider<Map<String, ? extends Location>> locations, ComputeUtils utils,
super(client, templateBuilderProvider, images, sizes, utils, successTester, notFoundTester); Predicate<String> successTester, @Named("NOT_FOUND") Predicate<VApp> notFoundTester,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
super(client, templateBuilderProvider, images, sizes, locations, utils, successTester,
notFoundTester, executor);
} }
@Override @Override

View File

@ -24,6 +24,7 @@ import java.net.InetAddress;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.concurrent.ExecutorService;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
@ -31,6 +32,7 @@ import javax.inject.Named;
import javax.inject.Provider; import javax.inject.Provider;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.Constants;
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.Size; import org.jclouds.compute.domain.Size;
@ -38,6 +40,7 @@ import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.domain.internal.NodeMetadataImpl; import org.jclouds.compute.domain.internal.NodeMetadataImpl;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.util.ComputeUtils; import org.jclouds.compute.util.ComputeUtils;
import org.jclouds.domain.Location;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.vcloud.compute.VCloudComputeService; import org.jclouds.vcloud.compute.VCloudComputeService;
import org.jclouds.vcloud.domain.VApp; import org.jclouds.vcloud.domain.VApp;
@ -65,10 +68,13 @@ public class TerremarkVCloudComputeService extends VCloudComputeService {
@Inject @Inject
public TerremarkVCloudComputeService(TerremarkVCloudClient client, public TerremarkVCloudComputeService(TerremarkVCloudClient client,
Provider<TemplateBuilder> templateBuilderProvider, Provider<TemplateBuilder> templateBuilderProvider,
Provider<Set<? extends Image>> images, Provider<Set<? extends Size>> sizes, Provider<Map<String, ? extends Image>> images,
ComputeUtils utils, Predicate<String> successTester, Provider<Map<String, ? extends Size>> sizes,
@Named("NOT_FOUND") Predicate<VApp> notFoundTester) { Provider<Map<String, ? extends Location>> locations, ComputeUtils utils,
super(client, templateBuilderProvider, images, sizes, utils, successTester, notFoundTester); Predicate<String> successTester, @Named("NOT_FOUND") Predicate<VApp> notFoundTester,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
super(client, templateBuilderProvider, images, sizes, locations, utils, successTester,
notFoundTester, executor);
this.client = client; this.client = client;
} }
@ -91,10 +97,11 @@ public class TerremarkVCloudComputeService extends VCloudComputeService {
@Override @Override
protected NodeMetadata getNodeMetadataByIdInVDC(String vDCId, String id) { protected NodeMetadata getNodeMetadataByIdInVDC(String vDCId, String id) {
VApp vApp = client.getVApp(id); VApp vApp = client.getVApp(id);
String tag = vApp.getName().replaceAll("-[0-9]+", "");
return new NodeMetadataImpl(vApp.getId(), vApp.getName(), vDCId, vApp.getLocation(), return new NodeMetadataImpl(vApp.getId(), vApp.getName(), vDCId, vApp.getLocation(),
ImmutableMap.<String, String> of(), vAppStatusToNodeState.get(vApp.getStatus()), ImmutableMap.<String, String> of(), tag,
getPublicAddresses(id), vApp.getNetworkToAddresses().values(), ImmutableMap vAppStatusToNodeState.get(vApp.getStatus()), getPublicAddresses(id), vApp
.<String, String> of()); .getNetworkToAddresses().values(), ImmutableMap.<String, String> of(), null);
} }
public InetAddress createPublicAddressMappedToPorts(String vAppId, int... ports) { public InetAddress createPublicAddressMappedToPorts(String vAppId, int... ports) {

View File

@ -18,15 +18,18 @@
*/ */
package org.jclouds.vcloud.terremark.compute.config; package org.jclouds.vcloud.terremark.compute.config;
import java.util.Set; import java.util.Map;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeoutException;
import javax.inject.Named; import javax.inject.Named;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeService;
import org.jclouds.compute.domain.Architecture; import org.jclouds.compute.domain.Architecture;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.Size; import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.internal.SizeImpl; import org.jclouds.compute.domain.internal.SizeImpl;
@ -37,8 +40,10 @@ import org.jclouds.vcloud.terremark.compute.TerremarkVCloudComputeService;
import org.jclouds.vcloud.terremark.domain.ComputeOptions; import org.jclouds.vcloud.terremark.domain.ComputeOptions;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.collect.ImmutableMap;
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.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.inject.Injector; import com.google.inject.Injector;
@ -65,21 +70,23 @@ public class TerremarkVCloudComputeServiceContextModule extends VCloudComputeSer
private static class ComputeOptionsToSize implements Function<ComputeOptions, Size> { private static class ComputeOptionsToSize implements Function<ComputeOptions, Size> {
@Override @Override
public Size apply(ComputeOptions from) { public Size apply(ComputeOptions from) {
return new SizeImpl(from.toString(), from.getProcessorCount(), from.getMemory(), 10, return new SizeImpl(from.toString(), from.toString(), null, null, ImmutableMap
.<String, String> of(), from.getProcessorCount(), from.getMemory(), 10,
ImmutableSet.<Architecture> of(Architecture.X86_32, Architecture.X86_64)); ImmutableSet.<Architecture> of(Architecture.X86_32, Architecture.X86_64));
} }
} }
@Override @Override
protected SortedSet<? extends Size> provideSizes(VCloudClient client, protected Map<String, ? extends Size> provideSizes(Function<ComputeMetadata, String> indexer,
Set<? extends Image> images, LogHolder holder, VCloudClient client, Map<String, ? extends Image> images, LogHolder holder,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) { @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor)
Image anyImage = Iterables.get(images, 0); throws InterruptedException, TimeoutException, ExecutionException {
Image anyImage = Iterables.get(images.values(), 0);
holder.logger.debug(">> providing sizes"); holder.logger.debug(">> providing sizes");
SortedSet<Size> sizes = Sets.newTreeSet(Iterables.transform(TerremarkVCloudClient.class.cast( SortedSet<Size> sizes = Sets.newTreeSet(Iterables.transform(TerremarkVCloudClient.class.cast(
client).getComputeOptionsOfCatalogItem(anyImage.getId()), sizeConverter)); client).getComputeOptionsOfCatalogItem(anyImage.getId()), sizeConverter));
holder.logger.debug("<< sizes(%d)", sizes.size()); holder.logger.debug("<< sizes(%d)", sizes.size());
return sizes; return Maps.uniqueIndex(sizes, indexer);
} }
} }