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;
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_AWS_EXPIREINTERVAL;
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 java.net.URI;
@ -40,6 +41,7 @@ public class EC2PropertiesBuilder extends PropertiesBuilder {
Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_EC2_ENDPOINT, "https://ec2.us-east-1.amazonaws.com");
properties.setProperty(PROPERTY_AWS_EXPIREINTERVAL, "60");
properties.setProperty(PROPERTY_EC2_AMI_OWNERS, "063491364108");
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.checkNotNull;
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.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import javax.annotation.Resource;
import javax.inject.Inject;
@ -33,39 +34,46 @@ import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.aws.AWSResponseException;
import org.jclouds.Constants;
import org.jclouds.aws.domain.Region;
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.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.IpProtocol;
import org.jclouds.aws.ec2.domain.KeyPair;
import org.jclouds.aws.ec2.domain.Reservation;
import org.jclouds.aws.ec2.domain.RunningInstance;
import org.jclouds.aws.ec2.options.RunInstancesOptions;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.ComputeType;
import org.jclouds.compute.domain.CreateNodeResponse;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeSet;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.domain.internal.ComputeMetadataImpl;
import org.jclouds.compute.domain.internal.CreateNodeResponseImpl;
import org.jclouds.compute.domain.internal.NodeMetadataImpl;
import org.jclouds.compute.options.RunNodeOptions;
import org.jclouds.compute.domain.internal.NodeSetImpl;
import org.jclouds.compute.options.TemplateOptions;
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 com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.internal.ImmutableSet;
/**
@ -73,128 +81,129 @@ import com.google.inject.internal.ImmutableSet;
*/
@Singleton
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
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
private final EC2Client ec2Client;
protected final Provider<Set<? extends Image>> images;
protected final Provider<Set<? extends Size>> sizes;
protected final EC2Client ec2Client;
protected final Map<RegionTag, KeyPairCredentials> credentialsMap;
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;
private final Predicate<RunningInstance> instanceStateRunning;
private final Predicate<RunningInstance> instanceStateTerminated;
private final RunningInstanceToNodeMetadata runningInstanceToNodeMetadata;
protected final Predicate<RunningInstance> instanceStateRunning;
protected final Predicate<RunningInstance> instanceStateTerminated;
protected final RunningInstanceToNodeMetadata runningInstanceToNodeMetadata;
protected final ExecutorService executor;
@Inject
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("TERMINATED") Predicate<RunningInstance> instanceStateTerminated,
RunningInstanceToNodeMetadata runningInstanceToNodeMetadata) {
RunningInstanceToNodeMetadata runningInstanceToNodeMetadata,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
this.templateBuilderProvider = templateBuilderProvider;
this.ec2Client = client;
this.images = images;
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.instanceStateTerminated = instanceStateTerminated;
this.runningInstanceToNodeMetadata = runningInstanceToNodeMetadata;
}
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);
this.executor = executor;
}
@Override
public CreateNodeResponse runNode(String name, Template template, RunNodeOptions options) {
checkArgument(template.getImage() instanceof EC2Image,
"unexpected image type. should be EC2Image, was: " + template.getImage().getClass());
public NodeSet runNodes(String tag, int count, Template template) {
checkArgument(tag.indexOf('-') == -1, "tag cannot contain hyphens");
checkArgument(template.getSize() instanceof EC2Size,
"unexpected image type. should be EC2Size, was: " + template.getSize().getClass());
EC2Image ec2Image = EC2Image.class.cast(template.getImage());
EC2Size ec2Size = EC2Size.class.cast(template.getSize());
Region region = ec2Image.getImage().getRegion();
KeyPair keyPair = createKeyPairInRegion(region, name);
String securityGroupName = name;
createSecurityGroupInRegion(region, securityGroupName, options.getOpenPorts());
// parse the availability zone of the request
AvailabilityZone zone = template.getLocation().getScope() == LocationScope.ZONE ? AvailabilityZone
.fromValue(template.getLocation().getId())
: null;
logger.debug(">> running instance region(%s) ami(%s) type(%s) keyPair(%s) securityGroup(%s)",
region, ec2Image.getId(), ec2Size.getInstanceType(), keyPair.getKeyName(),
securityGroupName);
RunInstancesOptions instanceOptions = withKeyName(keyPair.getKeyName())// key
// if the location has a parent, it must be an availability zone.
Region region = zone == null ? Region.fromValue(template.getLocation().getId()) : Region
.fromValue(template.getLocation().getParent());
// 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
.withSecurityGroup(securityGroupName)// group I created above
.withAdditionalInfo(name);
.withSecurityGroup(tag)// group I created above
.withAdditionalInfo(tag);
if (options.getRunScript() != null)
instanceOptions.withUserData(options.getRunScript());
RunningInstance runningInstance = Iterables.getOnlyElement(ec2Client.getInstanceServices()
.runInstancesInRegion(region, null, ec2Image.getId(), 1, 1, instanceOptions));
logger.debug("<< started instance(%s)", runningInstance.getId());
instanceStateRunning.apply(runningInstance);
logger.debug("<< running instance(%s)", runningInstance.getId());
Reservation reservation = ec2Client.getInstanceServices().runInstancesInRegion(region, zone,
template.getImage().getId(), 1, count, instanceOptions);
Iterable<String> ids = Iterables.transform(reservation, instanceToId);
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
runningInstance = getOnlyRunningInstanceInRegion(region, runningInstance.getId());
Set<InetAddress> publicAddresses = runningInstance.getIpAddress() == null ? ImmutableSet
.<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;
}
}
return new NodeSetImpl(Iterables.transform(Iterables.concat(ec2Client.getInstanceServices()
.describeInstancesInRegion(region, Iterables.toArray(ids, String.class))),
runningInstanceToNodeMetadata));
}
@Override
@ -208,114 +217,132 @@ public class EC2ComputeService implements ComputeService {
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) {
return Iterables
.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
public Set<ComputeMetadata> listNodes() {
public Map<String, NodeMetadata> getNodes() {
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)) {
Iterables.addAll(servers, Iterables.transform(Iterables.concat(ec2Client
Iterables.addAll(nodes, Iterables.transform(Iterables.concat(ec2Client
.getInstanceServices().describeInstancesInRegion(region)),
new Function<RunningInstance, ComputeMetadata>() {
@Override
public ComputeMetadata apply(RunningInstance from) {
return new ComputeMetadataImpl(ComputeType.NODE, from.getId(), from
.getKeyName(), from.getRegion().toString(), null, ImmutableMap
.<String, String> of());
}
}));
runningInstanceToNodeMetadata));
}
logger.debug("<< list(%d)", servers.size());
return servers;
return Maps.uniqueIndex(nodes, METADATA_TO_ID);
}
@Override
public void destroyNode(ComputeMetadata node) {
checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not "
+ node.getType());
checkNotNull(node.getId(), "node.id");
public void destroyNode(ComputeMetadata metadata) {
checkArgument(metadata.getType() == ComputeType.NODE, "this is only valid for nodes, not "
+ metadata.getType());
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);
for (RunningInstance runningInstance : getAllRunningInstancesInRegion(region, node.getId())) {
// grab the old keyname
String name = runningInstance.getKeyName();
RunningInstance instance = getInstance(node, region);
if (instance.getInstanceState() != InstanceState.TERMINATED) {
logger.debug(">> terminating instance(%s)", node.getId());
ec2Client.getInstanceServices().terminateInstancesInRegion(region, node.getId());
boolean success = instanceStateTerminated.apply(runningInstance);
boolean success = false;
while (!success) {
ec2Client.getInstanceServices().terminateInstancesInRegion(region, node.getId());
success = instanceStateTerminated.apply(getInstance(node, region));
}
logger.debug("<< terminated instance(%s) success(%s)", node.getId(), success);
logger.debug(">> deleting keyPair(%s)", name);
ec2Client.getKeyPairServices().deleteKeyPairInRegion(region, name);
logger.debug("<< deleted keyPair(%s)", name);
logger.debug(">> deleting securityGroup(%s)", name);
ec2Client.getSecurityGroupServices().deleteSecurityGroupInRegion(region, name);
logger.debug("<< deleted securityGroup(%s)", name);
}
if (Iterables.all(doGetNodes(tag), new Predicate<NodeMetadata>() {
@Override
public boolean apply(NodeMetadata input) {
return input.getState() == NodeState.TERMINATED;
}
})) {
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) {
Region region = node.getLocation() != null ? Region.fromValue(node.getLocation())
: Region.DEFAULT;
Location location = getLocations().get(node.getLocationId());
Region region = location.getScope() == LocationScope.REGION ? Region.fromValue(location
.getId()) : Region.fromValue(location.getParent());
return region;
}
@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();
}
@Override
public Set<? extends Image> listImages() {
public Map<String, ? extends Image> getImages() {
return images.get();
}

View File

@ -19,6 +19,7 @@
package org.jclouds.aws.ec2.compute.config;
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.util.Map;
@ -37,21 +38,36 @@ import org.jclouds.aws.ec2.EC2;
import org.jclouds.aws.ec2.EC2AsyncClient;
import org.jclouds.aws.ec2.EC2Client;
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.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.domain.AvailabilityZone;
import org.jclouds.compute.ComputeService;
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.OsFamily;
import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.internal.ImageImpl;
import org.jclouds.compute.internal.ComputeServiceContextImpl;
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.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.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.inject.Provides;
@ -68,6 +84,22 @@ public class EC2ComputeServiceContextModule extends EC2ContextModule {
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
@Singleton
ComputeServiceContext provideContext(ComputeService computeService,
@ -77,16 +109,47 @@ public class EC2ComputeServiceContextModule extends EC2ContextModule {
@Provides
@Singleton
Set<? extends Size> provideSizes() {
return ImmutableSet.of(EC2Size.C1_MEDIUM, EC2Size.C1_XLARGE, EC2Size.M1_LARGE,
EC2Size.M1_SMALL, EC2Size.M1_XLARGE, EC2Size.M2_2XLARGE, EC2Size.M2_4XLARGE);
Function<ComputeMetadata, String> indexer() {
return new Function<ComputeMetadata, String>() {
@Override
public String apply(ComputeMetadata from) {
return from.getId();
}
};
}
@Provides
@Singleton
@ResourceLocation
String getRegion(@EC2 Region region) {
return region.value();
Map<String, ? extends Size> provideSizes(Function<ComputeMetadata, String> indexer) {
return Maps.uniqueIndex(ImmutableSet.of(EC2Size.C1_MEDIUM, EC2Size.C1_XLARGE,
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 {
@ -101,13 +164,24 @@ public class EC2ComputeServiceContextModule extends EC2ContextModule {
@Provides
@Singleton
protected Set<? extends Image> provideImages(final EC2Client sync, Map<Region, URI> regionMap,
LogHolder holder) throws InterruptedException, ExecutionException, TimeoutException {
@Named(PROPERTY_EC2_AMI_OWNERS)
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();
holder.logger.debug(">> providing images");
for (final Region region : regionMap.keySet()) {
for (final org.jclouds.aws.ec2.domain.Image from : sync.getAMIServices()
.describeImagesInRegion(region, ownedBy("063491364108"))) {
.describeImagesInRegion(region, ownedBy(amiOwners))) {
OsFamily os = null;
String osDescription = from.getImageLocation();
String version = "";
@ -116,16 +190,28 @@ public class EC2ComputeServiceContextModule extends EC2ContextModule {
if (matcher.find()) {
try {
os = OsFamily.fromValue(matcher.group(1));
matcher.group(2);//TODO no field for os version
matcher.group(2);// TODO no field for os version
version = matcher.group(3);
} catch (IllegalArgumentException e) {
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());
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.internal.SizeImpl;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
/**
@ -34,11 +35,14 @@ import com.google.common.collect.ImmutableSet;
* @author Adrian Cole
*/
public class EC2Size extends SizeImpl {
/** The serialVersionUID */
private static final long serialVersionUID = 8605688733788974797L;
private final InstanceType instanceType;
EC2Size(InstanceType instanceType, Integer cores, Integer ram, Integer disk,
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;
}

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

View File

@ -19,6 +19,7 @@
package org.jclouds.aws.ec2.reference;
import org.jclouds.aws.reference.AWSConstants;
import org.jclouds.compute.ComputeService;
/**
* Configuration properties and constants used in EC2 connections.
@ -27,5 +28,10 @@ import org.jclouds.aws.reference.AWSConstants;
*/
public interface EC2Constants extends AWSConstants {
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,
@FormParam("KeyName") String keyName);
// map resourcenotfoundexception to empty set
/**
* @see KeyPairClient#describeKeyPairsInRegion
*/

View File

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

View File

@ -113,11 +113,9 @@ public interface BlobStore {
* fully qualified name relative to the container.
* @param 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
* if the container doesn't exist
* @throws KeyNotFoundException
* if the container doesn't exist
*/
Blob getBlob(String container, String name);

View File

@ -66,7 +66,7 @@ public interface StorageMetadata extends ResourceMetadata<StorageType> {
*
*/
@Override
String getLocation();
String getLocationId();
/**
* 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 byte[] contentMD5;
public BlobMetadataImpl(String id, String name, @Nullable String location, URI uri, String eTag,
Long size, Date lastModified, Map<String, String> userMetadata, String contentType,
byte[] contentMD5) {
public BlobMetadataImpl(String id, String name, @Nullable String location, URI uri,
String eTag, Long size, Date lastModified, Map<String, String> userMetadata,
String contentType, byte[] contentMD5) {
super(StorageType.BLOB, id, name, location, uri, eTag, size, lastModified, userMetadata);
this.contentType = contentType;
this.contentMD5 = contentMD5;

View File

@ -38,7 +38,7 @@ public class ResourceMetadataToRelativePathResourceMetadata implements
name = name.substring(0, name.length() - suffix.length());
}
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());
}

View File

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

View File

@ -18,16 +18,16 @@
*/
package org.jclouds.compute;
import java.util.Set;
import java.util.Map;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.CreateNodeResponse;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeSet;
import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.options.RunNodeOptions;
import org.jclouds.domain.Location;
/**
* Provides portable access to launching compute instances.
@ -42,36 +42,62 @@ public interface ComputeService {
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);
CreateNodeResponse runNode(String name, Template template, RunNodeOptions options);
NodeSet runNodes(String tag, int maxNodes, Template template);
/**
* 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);
/**
* destroy the nodes identified by this tag.
*/
void destroyNodes(String tag);
/**
* Find a node by its id
*/
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
public String getName();
/**
* location where the node exists..
*
*/
@Override
public String getLocation();
}

View File

@ -23,23 +23,22 @@
*/
package org.jclouds.compute.domain;
import org.jclouds.compute.domain.internal.ImageImpl;
import com.google.inject.ImplementedBy;
/**
* Running Operating system
*
* @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();
/**
* Description of the image
*/
String getDescription();
String getVersion();
/**
* Operating System
@ -51,16 +50,6 @@ public interface Image {
*/
String getOsDescription();
/**
* Version of the image
*/
String getVersion();
/**
* Geographic location of the image.
*/
String getLocation();
/**
* Operating System
*/

View File

@ -20,19 +20,44 @@ package org.jclouds.compute.domain;
import java.net.InetAddress;
import java.util.Map;
import java.util.SortedSet;
import java.util.Set;
import org.jclouds.domain.Credentials;
/**
* @author Adrian Cole
* @author Ivan Meredith
*/
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();
SortedSet<InetAddress> getPublicAddresses();
/**
* All public IP addresses, potentially including shared ips.
*/
Set<InetAddress> getPublicAddresses();
/**
* 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();
SortedSet<InetAddress> getPrivateAddresses();
/**
* Other variables present that the provider supports
*/

View File

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

View File

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

View File

@ -18,6 +18,9 @@
*/
package org.jclouds.compute.domain;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.domain.Location;
/**
* Configured operating system used to start nodes.
*
@ -35,4 +38,13 @@ public interface Template extends Cloneable {
*/
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;
import org.jclouds.compute.internal.TemplateBuilderImpl;
import org.jclouds.compute.options.TemplateOptions;
import com.google.inject.ImplementedBy;
@ -72,7 +73,7 @@ public interface TemplateBuilder {
/**
* 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
@ -121,4 +122,9 @@ public interface TemplateBuilder {
* Generate an immutable template from the current builder.
*/
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 */
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) {
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;
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.ComputeType;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.OsFamily;
/**
* @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 OsFamily operatingSystem;
private final String operatingSystemDescription;
private final String location;
private final OsFamily osFamily;
private final String osDescription;
private final Architecture architecture;
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((architecture == null) ? 0 : architecture.hashCode());
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;
public ImageImpl(String id, String name, String locationId, URI uri,
Map<String, String> userMetadata, String description, String version,
@Nullable OsFamily osFamily, String osDescription, Architecture architecture) {
super(ComputeType.IMAGE, id, name, locationId, uri, userMetadata);
this.version = checkNotNull(version, "version");
this.osFamily = osFamily;
this.osDescription = checkNotNull(osDescription, "osDescription");
this.architecture = checkNotNull(architecture, "architecture");
}
/**
@ -156,8 +70,16 @@ public class ImageImpl implements Image {
* {@inheritDoc}
*/
@Override
public String getLocation() {
return location;
public OsFamily getOsFamily() {
return osFamily;
}
/**
* {@inheritDoc}
*/
@Override
public String getOsDescription() {
return osDescription;
}
/**
@ -168,12 +90,4 @@ public class ImageImpl implements Image {
return architecture;
}
/**
* {@inheritDoc}
*/
@Override
public String getOsDescription() {
return operatingSystemDescription;
}
}

View File

@ -18,15 +18,19 @@
*/
package org.jclouds.compute.domain.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import java.net.InetAddress;
import java.net.URI;
import java.util.Comparator;
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.NodeMetadata;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.domain.Credentials;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
@ -40,47 +44,62 @@ public class NodeMetadataImpl extends ComputeMetadataImpl implements NodeMetadat
/** The serialVersionUID */
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 SortedSet<InetAddress> publicAddresses = Sets.newTreeSet(ADDRESS_COMPARATOR);
private final SortedSet<InetAddress> privateAddresses = Sets.newTreeSet(ADDRESS_COMPARATOR);
private final Set<InetAddress> publicAddresses = Sets.newLinkedHashSet();
private final Set<InetAddress> privateAddresses = Sets.newLinkedHashSet();
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,
Map<String, String> userMetadata, NodeState state,
public NodeMetadataImpl(String id, String name, String locationId, URI uri,
Map<String, String> userMetadata, String tag, NodeState state,
Iterable<InetAddress> publicAddresses, Iterable<InetAddress> privateAddresses,
Map<String, String> extra) {
super(ComputeType.NODE, id, name, location, uri, userMetadata);
this.state = state;
Iterables.addAll(this.publicAddresses, publicAddresses);
Iterables.addAll(this.privateAddresses, privateAddresses);
this.extra.putAll(extra);
Map<String, String> extra, @Nullable Credentials credentials) {
super(ComputeType.NODE, id, name, locationId, uri, userMetadata);
this.tag = checkNotNull(tag, "tag");
this.state = checkNotNull(state, "state");
Iterables.addAll(this.publicAddresses, checkNotNull(publicAddresses, "publicAddresses"));
Iterables.addAll(this.privateAddresses, checkNotNull(privateAddresses, "privateAddresses"));
this.extra.putAll(checkNotNull(extra, "extra"));
this.credentials = credentials;
}
/**
* {@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;
}
/**
* {@inheritDoc}
*/
public SortedSet<InetAddress> getPrivateAddresses() {
@Override
public Set<InetAddress> getPrivateAddresses() {
return privateAddresses;
}
/**
* {@inheritDoc}
*/
@Override
public NodeState getState() {
return state;
}
@ -95,20 +114,22 @@ public class NodeMetadataImpl extends ComputeMetadataImpl implements NodeMetadat
@Override
public String toString() {
return "[id=" + getId() + ", name=" + getName() + ", location=" + getLocation() + ", uri="
+ getUri() + ", userMetadata=" + getUserMetadata() + ", state=" + getState()
+ ", privateAddresses=" + privateAddresses + ", publicAddresses=" + publicAddresses
+ "]";
return "[id=" + getId() + ", tag=" + getTag() + ", name=" + getName() + ", location="
+ getLocationId() + ", uri=" + getUri() + ", userMetadata=" + getUserMetadata()
+ ", state=" + getState() + ", privateAddresses=" + privateAddresses
+ ", publicAddresses=" + publicAddresses + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((credentials == null) ? 0 : credentials.hashCode());
result = prime * result + ((extra == null) ? 0 : extra.hashCode());
result = prime * result + ((privateAddresses == null) ? 0 : privateAddresses.hashCode());
result = prime * result + ((publicAddresses == null) ? 0 : publicAddresses.hashCode());
result = prime * result + ((state == null) ? 0 : state.hashCode());
result = prime * result + ((tag == null) ? 0 : tag.hashCode());
return result;
}
@ -121,6 +142,11 @@ public class NodeMetadataImpl extends ComputeMetadataImpl implements NodeMetadat
if (getClass() != obj.getClass())
return false;
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 (other.extra != null)
return false;
@ -141,6 +167,11 @@ public class NodeMetadataImpl extends ComputeMetadataImpl implements NodeMetadat
return false;
} else if (!state.equals(other.state))
return false;
if (tag == null) {
if (other.tag != null)
return false;
} else if (!tag.equals(other.tag))
return false;
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;
import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
import org.jclouds.compute.domain.Architecture;
import org.jclouds.compute.domain.ComputeType;
import org.jclouds.compute.domain.Size;
import org.jclouds.domain.ResourceMetadata;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Iterables;
@ -30,20 +38,24 @@ import com.google.common.collect.Sets;
/**
* @author Adrian Cole
*/
public class SizeImpl implements Size {
private String id;
public class SizeImpl extends ComputeMetadataImpl implements Size {
/** The serialVersionUID */
private static final long serialVersionUID = 8994255275911717567L;
private final int cores;
private final int ram;
private final int disk;
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) {
this.id = id;
super(ComputeType.SIZE, id, name, location, uri, userMetadata);
this.cores = cores;
this.ram = ram;
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;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + cores;
result = prime * result + disk;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ram;
result = prime * result
+ ((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();
public int compareTo(ResourceMetadata<ComputeType> that) {
if (that instanceof Size) {
Size thatSize = Size.class.cast(that);
return ComparisonChain.start().compare(this.getCores(), thatSize.getCores()).compare(
this.getRam(), thatSize.getRam()).compare(this.getDisk(), thatSize.getDisk())
.result();
} else {
return super.compareTo(that);
}
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return "[id=" + id + ", cores=" + cores + ", ram=" + ram + ", disk=" + disk
return "[id=" + getId() + ", cores=" + cores + ", ram=" + ram + ", disk=" + disk
+ ", supportedArchitectures=" + supportedArchitectures + "]";
}
@ -126,15 +110,7 @@ public class SizeImpl implements Size {
* {@inheritDoc}
*/
@Override
public boolean supportsArchitecture(Architecture architecture) {
return supportedArchitectures.contains(architecture);
}
/**
* {@inheritDoc}
*/
@Override
public String getId() {
return id;
public Set<Architecture> getSupportedArchitectures() {
return supportedArchitectures;
}
}

View File

@ -23,9 +23,13 @@
*/
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.Size;
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 Size size;
private final Location location;
private final TemplateOptions options;
protected TemplateImpl(Image image, Size size) {
this.image = image;
this.size = size;
public TemplateImpl(Image image, Size size, Location location, TemplateOptions options) {
this.image = checkNotNull(image, "image");
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;
}
/**
* {@inheritDoc}
*/
@Override
public Location getLocation() {
return location;
}
/**
* {@inheritDoc}
*/
@Override
public TemplateOptions getOptions() {
return options;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
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());
return result;
}
@ -80,6 +106,16 @@ public class TemplateImpl implements Template {
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 (options == null) {
if (other.options != null)
return false;
} else if (!options.equals(other.options))
return false;
if (size == null) {
if (other.size != null)
return false;
@ -98,6 +134,7 @@ public class TemplateImpl implements Template {
*/
@Override
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,
RestContext<X, Y> providerSpecificContext) {
this.computeService = checkNotNull(computeService, "computeService");
this.providerSpecificContext = providerSpecificContext;
this.providerSpecificContext = checkNotNull(providerSpecificContext, "providerSpecificContext");;
}
public ComputeService getComputeService() {

View File

@ -1,21 +1,26 @@
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.Set;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import org.jclouds.compute.domain.Architecture;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.domain.internal.TemplateImpl;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.ResourceLocation;
import org.jclouds.domain.Location;
import org.jclouds.logging.Logger;
import com.google.common.base.Predicate;
@ -37,17 +42,17 @@ public class TemplateBuilderImpl implements TemplateBuilder {
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
private final Set<? extends Image> images;
private final Set<? extends Size> sizes;
private String location;
private final Map<String, ? extends Image> images;
private final Map<String, ? extends Size> sizes;
private final Map<String, ? extends Location> locations;
private OsFamily os;
private Architecture arch;
private String locationId;
private String imageId;
private String sizeId;
private String osDescription;
private String imageVersion;
private String imageDescription;
private String imageName;
private int minCores;
private int minRam;
@ -55,15 +60,29 @@ public class TemplateBuilderImpl implements TemplateBuilder {
private boolean biggest;
private boolean fastest;
private TemplateOptions options = TemplateOptions.NONE;
@Inject
public TemplateBuilderImpl(@ResourceLocation String location, Set<? extends Image> images,
Set<? extends Size> sizes) {
this.location = location;
public TemplateBuilderImpl(Map<String, ? extends Location> locations,
Map<String, ? extends Image> images, Map<String, ? extends Size> sizes,
Location defaultLocation) {
this.locations = locations;
this.images = images;
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
public boolean apply(Image input) {
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>() {
@Override
@ -136,15 +145,15 @@ public class TemplateBuilderImpl implements TemplateBuilder {
return returnVal;
}
};
private final Predicate<Image> imageDescriptionPredicate = new Predicate<Image>() {
private final Predicate<Image> imageNamePredicate = new Predicate<Image>() {
@Override
public boolean apply(Image input) {
boolean returnVal = true;
if (imageDescription != null) {
if (input.getDescription() == null)
if (imageName != null) {
if (input.getName() == null)
returnVal = false;
else
returnVal = input.getDescription().matches(imageDescription);
returnVal = input.getName().matches(imageName);
}
return returnVal;
}
@ -165,16 +174,16 @@ public class TemplateBuilderImpl implements TemplateBuilder {
}
};
private final Predicate<Image> imagePredicate = Predicates.and(imageIdPredicate,
locationPredicate, osPredicate, imageArchPredicate, osDescriptionPredicate,
imageVersionPredicate, imageDescriptionPredicate);
private final Predicate<Image> imagePredicate = Predicates.and(idPredicate, locationPredicate,
osPredicate, imageArchPredicate, osDescriptionPredicate, imageVersionPredicate,
imageNamePredicate);
private final Predicate<Size> sizeArchPredicate = new Predicate<Size>() {
@Override
public boolean apply(Size input) {
boolean returnVal = false;
if (arch != null)
returnVal = input.supportsArchitecture(arch);
returnVal = input.getSupportedArchitectures().contains(arch);
return returnVal;
}
};
@ -192,8 +201,8 @@ public class TemplateBuilderImpl implements TemplateBuilder {
return input.getRam() >= TemplateBuilderImpl.this.minRam;
}
};
private final Predicate<Size> sizePredicate = Predicates.and(sizeIdPredicate, sizeArchPredicate,
sizeCoresPredicate, sizeRamPredicate);
private final Predicate<Size> sizePredicate = Predicates.and(sizeIdPredicate, locationPredicate,
sizeArchPredicate, sizeCoresPredicate, sizeRamPredicate);
static final Ordering<Size> DEFAULT_SIZE_ORDERING = new Ordering<Size>() {
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>() {
public int compare(Image left, Image right) {
return ComparisonChain.start().compare(left.getOsDescription(),
right.getOsDescription()).compare(left.getVersion(), right.getVersion())
.result();
return ComparisonChain.start().compare(left.getOsDescription(), right.getOsDescription())
.compare(left.getVersion(), right.getVersion()).result();
}
};
@ -229,6 +237,8 @@ public class TemplateBuilderImpl implements TemplateBuilder {
*/
@Override
public TemplateBuilder fromSize(Size size) {
if (size.getLocationId() != null)
this.locationId = size.getLocationId();
this.minCores = size.getCores();
this.minRam = size.getRam();
return this;
@ -239,8 +249,8 @@ public class TemplateBuilderImpl implements TemplateBuilder {
*/
@Override
public TemplateBuilder fromImage(Image image) {
if (image.getLocation() != null)
this.location = image.getLocation();
if (image.getLocationId() != null)
this.locationId = image.getLocationId();
if (image.getOsFamily() != null)
this.os = image.getOsFamily();
if (image.getOsDescription() != null)
@ -283,8 +293,10 @@ public class TemplateBuilderImpl implements TemplateBuilder {
* {@inheritDoc}
*/
@Override
public TemplateBuilder location(String location) {
this.location = location;
public TemplateBuilder locationId(final String locationId) {
checkArgument(locations.get(checkNotNull(locationId, "locationId")) != null, "locationId "
+ locationId + " not configured in: " + locations.keySet());
this.locationId = locationId;
return this;
}
@ -314,7 +326,7 @@ public class TemplateBuilderImpl implements TemplateBuilder {
logger.debug(">> searching params(%s)", this);
Image image;
try {
image = DEFAULT_IMAGE_ORDERING.max(Iterables.filter(images, imagePredicate));
image = DEFAULT_IMAGE_ORDERING.max(Iterables.filter(images.values(), imagePredicate));
} catch (NoSuchElementException exception) {
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));
Size size;
try {
size = sizeOrdering.max(Iterables.filter(sizes, sizePredicate));
size = sizeOrdering.max(Iterables.filter(sizes.values(), sizePredicate));
} catch (NoSuchElementException exception) {
throw new NoSuchElementException("size didn't match: " + toString() + "\n" + sizes);
}
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
public TemplateBuilder imageDescriptionMatches(String descriptionRegex) {
this.imageDescription = descriptionRegex;
this.imageName = descriptionRegex;
return this;
}
@ -401,13 +414,22 @@ public class TemplateBuilderImpl implements TemplateBuilder {
return this;
}
/**
* {@inheritDoc}
*/
@Override
public TemplateBuilder options(TemplateOptions options) {
this.options = checkNotNull(options, "options");
return this;
}
@Override
public String toString() {
return "[arch=" + arch + ", biggest=" + biggest + ", fastest=" + fastest
+ ", imageDescription=" + imageDescription + ", imageId=" + imageId
+ ", imageVersion=" + imageVersion + ", location=" + location + ", minCores="
+ minCores + ", minRam=" + minRam + ", os=" + os + ", osDescription=" + osDescription
+ ", sizeId=" + sizeId + "]";
+ ", imageDescription=" + imageName + ", imageId=" + imageId + ", imageVersion="
+ imageVersion + ", location=" + locationId + ", minCores=" + minCores + ", minRam="
+ minRam + ", os=" + os + ", osDescription=" + osDescription + ", 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.net.ConnectException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.Comparator;
import javax.annotation.Resource;
import javax.inject.Named;
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.logging.Logger;
import org.jclouds.ssh.SshClient;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
@ -50,6 +53,13 @@ public class ComputeUtils {
private SshClient.Factory sshFactory;
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
public ComputeUtils(Predicate<InetSocketAddress> 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");
InetSocketAddress socket = new InetSocketAddress(node.getPublicAddresses().last(), 22);
InetSocketAddress socket = new InetSocketAddress(Iterables.get(node.getPublicAddresses(), 0),
22);
socketTester.apply(socket);
SshClient ssh = isKeyAuth(node) ? sshFactory.create(socket, node.getCredentials().account,
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";
ssh.put(scriptName, new ByteArrayInputStream(script));
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
&& 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.net.InetSocketAddress;
import java.util.NoSuchElementException;
import java.util.SortedSet;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.ComputeType;
import org.jclouds.compute.domain.CreateNodeResponse;
import org.jclouds.compute.domain.Image;
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.Size;
import org.jclouds.compute.domain.Template;
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.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.predicates.RetryablePredicate;
@ -56,6 +59,7 @@ import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
@ -71,11 +75,10 @@ public abstract class BaseComputeServiceLiveTest {
protected String service;
protected SshClient.Factory sshFactory;
protected RunNodeOptions options = RunNodeOptions.Builder.openPorts(22);
protected String nodeName;
protected String tag;
private RetryablePredicate<InetSocketAddress> socketTester;
private CreateNodeResponse node;
private SortedSet<NodeMetadata> nodes;
protected ComputeServiceContext context;
protected ComputeService client;
protected String user;
@ -85,7 +88,8 @@ public abstract class BaseComputeServiceLiveTest {
@BeforeGroups(groups = { "live" })
public void setupClient() throws InterruptedException, ExecutionException, TimeoutException,
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");
password = checkNotNull(System.getProperty("jclouds.test.key"), "jclouds.test.key");
context = new ComputeServiceContextFactory().createContext(service, user, password,
@ -108,12 +112,7 @@ public abstract class BaseComputeServiceLiveTest {
@Test(enabled = true)
public void testCreate() throws Exception {
try {
client.destroyNode(Iterables.find(client.listNodes(), new Predicate<ComputeMetadata>() {
@Override
public boolean apply(ComputeMetadata input) {
return input.getName().equals(nodeName);
}
}));
client.destroyNodes(tag);
} catch (HttpResponseException e) {
// TODO hosting.com throws 400 when we try to delete a vApp
} catch (NoSuchElementException e) {
@ -122,75 +121,133 @@ public abstract class BaseComputeServiceLiveTest {
template = buildTemplate(client.templateBuilder());
if (canRunScript(template))
options.runScript(new ScriptBuilder()
// update add dns and install jdk
.addStatement(
Statements.exec("echo nameserver 208.67.222.222 >> /etc/resolv.conf"))
.addStatement(Statements.exec("apt-get update"))//
.addStatement(Statements.exec("apt-get upgrade -y"))//
.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("chmod 755 /usr/bin/runurl"))//
.build(org.jclouds.scriptbuilder.domain.OsFamily.UNIX).getBytes());
node = client.runNode(nodeName, template, options);
assertNotNull(node.getId());
assertNotNull(node.getName());
assert node.getPublicAddresses().size() >= 1: "no public ips in" + node;
assertNotNull(node.getCredentials());
if (node.getCredentials().account != null) {
assertNotNull(node.getCredentials().account);
assertNotNull(node.getCredentials().key);
sshPing();
template
.getOptions()
.runScript(
new ScriptBuilder()
// update add dns and install jdk
.addStatement(
Statements
.exec("echo nameserver 208.67.222.222 >> /etc/resolv.conf"))
.addStatement(Statements.exec("apt-get update"))
//
.addStatement(Statements.exec("apt-get upgrade -y"))
//
.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("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.getTag());
assertEquals(node.getTag(), tag);
assert node.getPublicAddresses().size() >= 1 || node.getPrivateAddresses().size() >= 1 : "no ips in"
+ node;
assertNotNull(node.getCredentials());
if (node.getCredentials().account != null) {
assertNotNull(node.getCredentials().account);
assertNotNull(node.getCredentials().key);
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);
@Test(enabled = true, dependsOnMethods = "testCreate")
public void testGet() throws Exception {
NodeMetadata metadata = client.getNodeMetadata(node);
assertEquals(metadata.getId(), node.getId());
assertEquals(metadata.getName(), node.getName());
assertEquals(metadata.getPrivateAddresses(), node.getPrivateAddresses());
assertEquals(metadata.getPublicAddresses(), node.getPublicAddresses());
NodeSet metadataSet = client.getNodes(tag);
for (NodeMetadata node : nodes) {
metadataSet.remove(node);
NodeMetadata metadata = client.getNodeMetadata(node);
assertEquals(metadata.getId(), node.getId());
assertEquals(metadata.getName(), node.getName());
assertEquals(metadata.getPrivateAddresses(), node.getPrivateAddresses());
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 {
for (ComputeMetadata node : client.listNodes()) {
assert node.getId() != null;
assert node.getLocation() != null;
assertEquals(node.getType(), ComputeType.NODE);
for (Entry<String, ? extends ComputeMetadata> node : client.getNodes().entrySet()) {
assertEquals(node.getKey(), node.getValue().getId());
assert node.getValue().getId() != null;
assert node.getValue().getLocationId() != null;
assertEquals(node.getValue().getType(), ComputeType.NODE);
}
}
public void testListImages() throws Exception {
for (Image image : client.listImages()) {
assert image.getId() != null : image;
assert image.getLocation() != null : image;
for (Entry<String, ? extends Image> image : client.getImages().entrySet()) {
assertEquals(image.getKey(), image.getValue().getId());
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 {
for (Size size : client.listSizes()) {
assert size.getCores() > 0 : size;
for (Entry<String, ? extends Size> size : client.getSizes().entrySet()) {
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 {
try {
doCheckKey();
} catch (SshException e) {// try twice in case there is a network timeout
private void sshPing(NodeMetadata node) throws IOException {
for (int i = 0; i < 5; i++) {// retry loop TODO replace with predicate.
try {
Thread.sleep(10 * 1000);
} catch (InterruptedException e1) {
doCheckKey(node);
return;
} catch (SshException e) {
try {
Thread.sleep(10 * 1000);
} catch (InterruptedException e1) {
}
continue;
}
doCheckKey();
}
}
private void doCheckKey() throws IOException {
InetSocketAddress socket = new InetSocketAddress(node.getPublicAddresses().last(), 22);
socketTester.apply(socket);
private void doCheckKey(NodeMetadata node) throws IOException {
InetSocketAddress socket = new InetSocketAddress(Iterables.get(node.getPublicAddresses(), 0),
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
.create(socket, node.getCredentials().account, node.getCredentials().key.getBytes())
: sshFactory
@ -209,8 +266,12 @@ public abstract class BaseComputeServiceLiveTest {
@AfterTest
protected void cleanup() throws InterruptedException, ExecutionException, TimeoutException {
if (node != null)
client.destroyNode(node);
if (nodes != null) {
client.destroyNodes(tag);
for (NodeMetadata node : client.getNodes(tag)) {
assert node.getState() == NodeState.TERMINATED : node;
}
}
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) {
return String.format("%s, completed: %d/%d, errors: %d, rate: %f ops/sec%n", prefix,
complete, size, errors, ((double) complete)
/ ((System.currentTimeMillis() - start) / 1000.0));
return String
.format("%s, completed: %d/%d, errors: %d, rate: %fms/op%n", prefix, complete,
size, errors, ((System.currentTimeMillis() - start) / ((double) size)));
}
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
*/
void setLocation(String location);
void setLocationId(String location);
/**
* @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();
/**
* Physical location of the resource.
* Physical location of the resource, or null if n/a
*
* ex. us-west-1
*
*/
String getLocation();
String getLocationId();
/**
* URI used to access this resource
@ -69,4 +69,5 @@ public interface ResourceMetadata<T extends Enum<T>> extends Comparable<Resource
*/
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.id = from.getId();
this.name = from.getName();
this.location = from.getLocation();
this.location = from.getLocationId();
this.uri = from.getUri();
this.userMetadata = from.getUserMetadata();
}
@ -156,7 +156,7 @@ public class MutableResourceMetadataImpl<T extends Enum<T>> implements MutableRe
* {@inheritDoc}
*/
@Override
public void setLocation(String location) {
public void setLocationId(String location) {
this.location = location;
}
@ -164,7 +164,7 @@ public class MutableResourceMetadataImpl<T extends Enum<T>> implements MutableRe
* {@inheritDoc}
*/
@Override
public String getLocation() {
public String getLocationId() {
return location;
}

View File

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

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

View File

@ -18,6 +18,7 @@
*/
package org.jclouds.rackspace.cloudservers.compute.config;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@ -33,24 +34,30 @@ import org.jclouds.Constants;
import org.jclouds.compute.ComputeService;
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.OsFamily;
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.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.rackspace.cloudservers.CloudServersAsyncClient;
import org.jclouds.rackspace.cloudservers.CloudServersClient;
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.domain.Flavor;
import org.jclouds.rackspace.cloudservers.options.ListOptions;
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.Maps;
import com.google.common.collect.Sets;
import com.google.inject.Provides;
@ -78,25 +85,44 @@ public class CloudServersComputeServiceContextModule extends CloudServersContext
@Provides
@Singleton
@ResourceLocation
String getRegion() {
return "default";
Location getRegion() {
return new LocationImpl(LocationScope.ZONE, "DALLAS", "Dallas, TX", null, true);
}
@Provides
@Singleton
protected Set<? extends Size> provideSizes(CloudServersClient sync, Set<? extends Image> images,
LogHolder holder, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor)
throws InterruptedException, TimeoutException, ExecutionException {
Map<String, ? extends Location> provideLocations(Location location) {
return ImmutableMap.of(location.getId(), location);
}
@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();
holder.logger.debug(">> providing sizes");
for (final Flavor from : sync.listFlavors(ListOptions.Builder.withDetails())) {
sizes.add(new CloudServersSize(from, from.getId() + "", from.getDisk() / 10,
from.getRam(), from.getDisk(), ImmutableSet.<Architecture> of(
Architecture.X86_32, Architecture.X86_64)));
sizes.add(new SizeImpl(from.getId() + "", from.getName(), location.getId(), null,
ImmutableMap.<String, String> of(), from.getDisk() / 10, from.getRam(), from
.getDisk(), ImmutableSet.<Architecture> of(Architecture.X86_32,
Architecture.X86_64)));
}
holder.logger.debug("<< sizes(%d)", sizes.size());
return sizes;
return Maps.uniqueIndex(sizes, indexer);
}
private static class LogHolder {
@ -109,9 +135,9 @@ public class CloudServersComputeServiceContextModule extends CloudServersContext
@Provides
@Singleton
protected Set<? extends Image> provideImages(final CloudServersClient sync,
@ResourceLocation String location, LogHolder holder) throws InterruptedException,
ExecutionException, TimeoutException {
protected Map<String, ? extends Image> provideImages(final CloudServersClient sync,
Location location, LogHolder holder, Function<ComputeMetadata, String> indexer)
throws InterruptedException, ExecutionException, TimeoutException {
final Set<Image> images = Sets.newHashSet();
holder.logger.debug(">> providing images");
for (final org.jclouds.rackspace.cloudservers.domain.Image from : sync
@ -120,7 +146,6 @@ public class CloudServersComputeServiceContextModule extends CloudServersContext
Architecture arch = Architecture.X86_64;
String osDescription = "";
String version = "";
Matcher matcher = RACKSPACE_PATTERN.matcher(from.getName());
osDescription = from.getName();
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));
}
}
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());
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.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.UnknownHostException;
import java.util.Map;
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.inject.Inject;
@ -31,22 +38,24 @@ import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.ComputeType;
import org.jclouds.compute.domain.CreateNodeResponse;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeSet;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.domain.internal.CreateNodeResponseImpl;
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.util.ComputeUtils;
import org.jclouds.concurrent.ConcurrentUtils;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.ResourceLocation;
import org.jclouds.domain.Location;
import org.jclouds.logging.Logger;
import org.jclouds.rimuhosting.miro.RimuHostingClient;
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.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.ListenableFuture;
/**
* @author Ivan Meredith
*/
@Singleton
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
static Iterable<InetAddress> getPublicAddresses(Server server) {
@ -122,20 +95,91 @@ public class RimuHostingComputeService implements ComputeService {
});
}
public Set<ComputeMetadata> listNodes() {
Set<ComputeMetadata> serverSet = Sets.newLinkedHashSet();
Set<Server> servers = client.getServerList();
for (Server server : servers) {
serverSet.add(toNode(server));
private static class NodeMatchesTag implements Predicate<NodeMetadata> {
private final String tag;
@Override
public boolean apply(NodeMetadata from) {
return from.getTag().equals(tag);
}
return serverSet;
public NodeMatchesTag(String tag) {
super();
this.tag = tag;
}
};
@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;
}
private NodeMetadataImpl toNode(Server server) {
return new NodeMetadataImpl(server.getId() + "", server.getName(), location, null,
ImmutableMap.<String, String> of(), NodeState.UNKNOWN, getPublicAddresses(server),
ImmutableList.<InetAddress> of(), ImmutableMap.<String, String> of("state", server
.getState()));
@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
@ -143,7 +187,7 @@ public class RimuHostingComputeService implements ComputeService {
checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not "
+ node.getType());
checkNotNull(node.getId(), "node.id");
return toNode(client.getServer(Long.parseLong(node.getId())));
return serverToNodeMetadata.apply(client.getServer(Long.parseLong(node.getId())));
}
@Override
@ -151,21 +195,110 @@ public class RimuHostingComputeService implements ComputeService {
checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not "
+ node.getType());
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()));
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
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();
}
@Override
public Set<? extends Image> listImages() {
public Map<String, ? extends Image> getImages() {
return images.get();
}
@Override
public TemplateBuilder templateBuilder() {
return this.templateBuilderProvider.get();
return templateBuilderProvider.get();
}
}

View File

@ -18,6 +18,7 @@
*/
package org.jclouds.rimuhosting.miro.compute.config;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@ -33,6 +34,7 @@ import org.jclouds.Constants;
import org.jclouds.compute.ComputeService;
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.OsFamily;
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.internal.ComputeServiceContextImpl;
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.rest.RestContext;
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.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.Maps;
import com.google.common.collect.Sets;
import com.google.inject.Provides;
@ -77,25 +84,66 @@ public class RimuHostingComputeServiceContextModule extends RimuHostingContextMo
@Provides
@Singleton
@ResourceLocation
String getRegion() {
return "default";
Location getDefaultLocation(Map<String, ? extends Location> locations) {
return locations.get("DCDALLAS");
}
@Provides
@Singleton
protected Set<? extends Size> provideSizes(RimuHostingClient sync, Set<? extends Image> images,
LogHolder holder, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userExecutor) throws InterruptedException,
Map<String, ? extends Location> getDefaultLocations(RimuHostingClient sync, LogHolder holder,
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 {
final Set<Size> sizes = Sets.newHashSet();
holder.logger.debug(">> providing sizes");
for (final PricingPlan from : sync.getPricingPlanList()) {
sizes.add(new SizeImpl(from.getId(), from.getDiskSize(), from.getRam(),
from.getDiskSize(), ImmutableSet.<Architecture> of(Architecture.X86_32,
Architecture.X86_64)));
try {
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)));
} catch (NullPointerException e) {
holder.logger.warn("datacenter not present in " + from.getId());
}
}
holder.logger.debug("<< sizes(%d)", sizes.size());
return sizes;
return Maps.uniqueIndex(sizes, indexer);
}
private static class LogHolder {
@ -108,9 +156,9 @@ public class RimuHostingComputeServiceContextModule extends RimuHostingContextMo
@Provides
@Singleton
protected Set<? extends Image> provideImages(final RimuHostingClient sync,
@ResourceLocation String location, LogHolder holder) throws InterruptedException,
ExecutionException, TimeoutException {
protected Map<String, ? extends Image> provideImages(final RimuHostingClient sync,
LogHolder holder, Function<ComputeMetadata, String> indexer)
throws InterruptedException, ExecutionException, TimeoutException {
final Set<Image> images = Sets.newHashSet();
holder.logger.debug(">> providing images");
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));
}
}
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());
return images;
return Maps.uniqueIndex(images, indexer);
}
}

View File

@ -18,10 +18,13 @@
*/
package org.jclouds.rimuhosting.miro.config;
import com.google.common.base.Predicate;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import org.jclouds.concurrent.internal.SyncProxy;
import org.jclouds.http.RequiresHttp;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.predicates.SocketOpen;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.RestClientFactory;
import org.jclouds.rimuhosting.miro.RimuHosting;
@ -33,17 +36,25 @@ import org.jclouds.rimuhosting.miro.reference.RimuHostingConstants;
import javax.inject.Named;
import javax.inject.Singleton;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.URI;
import java.util.concurrent.TimeUnit;
/**
* Configures the RimuHosting connection.
*
*
* @author Adrian Cole
*/
@RequiresHttp
@ConfiguresRestClient
public class RimuHostingRestClientModule extends AbstractModule {
@Provides
@Singleton
protected Predicate<InetSocketAddress> socketTester(SocketOpen open) {
return new RetryablePredicate<InetSocketAddress>(open, 130, 1, TimeUnit.SECONDS);
}
@Override
protected void configure() {
bindErrorHandlers();
@ -53,8 +64,8 @@ public class RimuHostingRestClientModule extends AbstractModule {
@Provides
@Singleton
public RimuHostingAuthentication provideRimuHostingAuthentication(
@Named(RimuHostingConstants.PROPERTY_RIMUHOSTING_APIKEY) String apikey)
throws UnsupportedEncodingException {
@Named(RimuHostingConstants.PROPERTY_RIMUHOSTING_APIKEY) String apikey)
throws UnsupportedEncodingException {
return new RimuHostingAuthentication(apikey);
}
@ -66,15 +77,16 @@ public class RimuHostingRestClientModule extends AbstractModule {
@Provides
@Singleton
public RimuHostingClient provideClient(RimuHostingAsyncClient client) throws IllegalArgumentException,
SecurityException, NoSuchMethodException {
public RimuHostingClient provideClient(RimuHostingAsyncClient client)
throws IllegalArgumentException, SecurityException, NoSuchMethodException {
return SyncProxy.create(RimuHostingClient.class, client);
}
@Provides
@Singleton
@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);
}

View File

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

View File

@ -1,32 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
<!--
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");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
====================================================================
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.
====================================================================
-->
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.
====================================================================
-->
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<!--
For more configuration infromation and examples see the Apache Log4j
website: http://logging.apache.org/log4j/
-->
<!--
For more configuration infromation and examples see the Apache
Log4j website: http://logging.apache.org/log4j/
-->
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
debug="false">
debug="false">
<!-- A time/date based rolling appender -->
<appender name="WIREFILE" class="org.apache.log4j.DailyRollingFileAppender">
@ -39,56 +38,88 @@
<param name="Threshold" value="TRACE" />
<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" />
<!--
The full pattern: Date MS Priority [Category] (Thread:NDC) Message${symbol_escape}n
<param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x)
%m%n"/>
The full pattern: Date MS Priority [Category]
(Thread:NDC) Message${symbol_escape}n <param
name="ConversionPattern" value="%d %-5r %-5p [%c]
(%t:%x) %m%n"/>
-->
</layout>
</appender>
<!-- A time/date based rolling appender -->
<appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds.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${symbol_escape}n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category] (Thread:NDC) Message${symbol_escape}n
<param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x)
%m%n"/>
-->
</layout>
</appender>
<appender name="ASYNC" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="FILE" />
</appender>
<!-- A time/date based rolling appender -->
<appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds.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${symbol_escape}n
-->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category]
(Thread:NDC) Message${symbol_escape}n <param
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>
</appender>
<appender name="ASYNCCOMPUTE" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="COMPUTEFILE" />
</appender>
<appender name="ASYNC" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="FILE" />
</appender>
<appender name="ASYNCWIRE" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="WIREFILE" />
</appender>
<!-- ================ -->
<!-- Limit categories -->
<!-- ================ -->
<category name="org.jclouds">
<priority value="DEBUG" />
</appender>
<!-- ================ -->
<!-- Limit categories -->
<!-- ================ -->
<category name="org.jclouds">
<priority value="DEBUG" />
<appender-ref ref="ASYNC" />
</category>
</category>
<category name="jclouds.headers">
<priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" />
@ -98,13 +129,18 @@
<priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" />
</category>
<!-- ======================= -->
<!-- Setup the Root category -->
<!-- ======================= -->
<root>
<priority value="WARN" />
</root>
<category name="jclouds.compute">
<priority value="TRACE" />
<appender-ref ref="ASYNCCOMPUTE" />
</category>
<!-- ======================= -->
<!-- Setup the Root category -->
<!-- ======================= -->
<root>
<priority value="WARN" />
</root>
</log4j:configuration>

View File

@ -2,4 +2,4 @@ service=ec2
driver=aws
account=accesskeyid
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
account=user@youregistered.com
key=password
nodename=name_of_your_vapp
nodetag=name_of_your_vapp

View File

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

View File

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

View File

@ -2,4 +2,4 @@ service=terremark
driver=terremark
account=user@youregistered.com
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
account=user@youregistered.com
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 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}"/>
<target name="destroy" description="destroy the node ${nodename}">
<compute action="destroy" provider="${url}">
<node name="${nodename}" />
<target name="destroy" description="destroy the nodes ${nodetag}">
<compute actions="destroy" provider="${url}">
<nodes tag="${nodetag}" />
</compute>
<sleep seconds="5" />
</target>
<target name="create" description="create the node ${nodename}" depends="destroy" >
<compute action="create" provider="${url}">
<node name="${nodename}" os="UBUNTU" size="SMALLEST"
<target name="create" description="create the nodes ${nodetag}" >
<compute actions="destroy,create" provider="${url}">
<nodes tag="${nodetag}" os="UBUNTU" size="SMALLEST"
runscript="runscript.sh" openports="22,${listenport}"
hostproperty="host" usernameproperty="username" passwordproperty="password" />
</compute>
</target>
<target name="cargooverssh" depends="create" description="run cargo on remote node" >
<echo message="deploying tomcat and blaze to: ${nodename}" />
<target name="cargooverssh" depends="create" description="run cargo on remote nodes" >
<echo message="deploying tomcat and blaze to: ${nodetag}" />
<cargo containerId="tomcat6x" output="build/output.log" log="build/cargo.log" action="start" timeout="600000">
<zipurlinstaller installurl="${container.zip}" />
<configuration home="build/cargo" type="standalone">

View File

@ -2,4 +2,4 @@ service=ec2
driver=aws
account=accesskeyid
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
account=user@youregistered.com
key=password
nodename=name_of_your_vapp
nodetag=name_of_your_vapp

View File

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

View File

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

View File

@ -2,4 +2,4 @@ service=terremark
driver=terremark
account=user@youregistered.com
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
account=user@youregistered.com
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}" />
<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 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 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 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 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
message="Which node do you wish to destroy"
addproperty="nodename"
addproperty="nodetag"
/>
<compute action="destroy" provider="${jclouds.compute.url}">
<node name="${nodename}" />
<compute actions="destroy" provider="${jclouds.compute.url}">
<node tag="${nodetag}" />
</compute>
</target>
<target name="get" description="get the node ${nodename}">
<target name="get" description="get the node ${nodetag}">
<input
message="Which node do you wish to describe?"
addproperty="nodename"
addproperty="nodetag"
/>
<compute action="get" provider="${jclouds.compute.url}">
<node name="${nodename}" />
<compute actions="get" provider="${jclouds.compute.url}">
<node tag="${nodetag}" />
</compute>
</target>
<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" />
<input
message="What do you want to name your node?"
addproperty="nodename"
addproperty="nodetag"
/>
<compute action="create" provider="${jclouds.compute.url}">
<node name="${nodename}" location="${location}" os="${os}" size="SMALLEST" hostproperty="host" usernameproperty="username" passwordproperty="password" />
<compute actions="create" provider="${jclouds.compute.url}">
<node tag="${nodetag}" location="${location}" os="${os}" size="SMALLEST" hostproperty="host" usernameproperty="username" passwordproperty="password" />
</compute>
</target>

View File

@ -18,11 +18,9 @@
*/
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.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.getNodeOptionsFromElement;
import static org.jclouds.tools.ant.taskdefs.compute.ComputeTaskUtils.ipOrEmptyString;
import java.io.File;
@ -39,15 +37,16 @@ import org.apache.tools.ant.Task;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.CreateNodeResponse;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.options.RunNodeOptions;
import org.jclouds.domain.Location;
import org.jclouds.http.HttpUtils;
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.inject.Provider;
@ -59,7 +58,7 @@ public class ComputeTask extends Task {
private final Map<URI, ComputeServiceContext> computeMap;
private String provider;
private String action;
private String actions;
private NodeElement nodeElement;
/**
@ -82,7 +81,7 @@ public class ComputeTask extends Task {
}
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 {
ComputeServiceContext context = computeMap.get(HttpUtils.createUri(provider));
Action action = Action.valueOf(CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE,
this.action));
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 {
context.close();
}
@ -132,6 +134,9 @@ public class ComputeTask extends Task {
case LIST_SIZES:
listSizes(computeService);
break;
case LIST_LOCATIONS:
listLocations(computeService);
break;
default:
this.log("bad action: " + action, Project.MSG_ERR);
}
@ -139,7 +144,7 @@ public class ComputeTask extends Task {
private void listDetails(ComputeService computeService) {
log("list details");
for (ComputeMetadata node : computeService.listNodes()) {// TODO
for (ComputeMetadata node : computeService.getNodes().values()) {// TODO
// parallel
logDetails(computeService, node);
}
@ -147,58 +152,67 @@ public class ComputeTask extends Task {
private void listImages(ComputeService computeService) {
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",
image.getLocation(), image.getId(), image.getVersion(), image.getArchitecture(),
image.getOsFamily(), image.getOsDescription()));
image.getLocationId(), image.getId(), image.getVersion(),
image.getArchitecture(), image.getOsFamily(), image.getOsDescription()));
}
}
private void listSizes(ComputeService computeService) {
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
.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) {
log("list");
for (ComputeMetadata node : computeService.listNodes()) {
log(String.format(" location=%s, id=%s, name=%s", node.getLocation(), node.getId(), node
.getName()));
for (ComputeMetadata node : computeService.getNodes().values()) {
log(String.format(" location=%s, id=%s, tag=%s", node.getLocationId(), node.getId(),
node.getName()));
}
}
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(),
nodeElement.getOs()));
log(String.format("create tag: %s, count: %d, size: %s, os: %s", tag, nodeElement.getCount(),
nodeElement.getSize(), nodeElement.getOs()));
Template template = createTemplateFromElement(nodeElement, computeService);
RunNodeOptions options = getNodeOptionsFromElement(nodeElement);
CreateNodeResponse createdNode = computeService.runNode(name, template, options);
NodeMetadata createdNode = Iterables.getOnlyElement(computeService.runNodes(tag, nodeElement
.getCount(), template));
logNodeDetails(createdNode);
addNodeDetailsAsProjectProperties(createdNode);
}
private void logNodeDetails(CreateNodeResponse createdNode) {
log(String.format(" id=%s, name=%s, connection=%s:%s@%s", createdNode.getId(), createdNode
.getName(), createdNode.getCredentials().account, createdNode.getCredentials().key,
createdNode.getPublicAddresses().first().getHostAddress()));
private void logNodeDetails(NodeMetadata createdNode) {
log(String.format(" id=%s, tag=%s, location=%s, tag=%s, connection=%s:%s@%s", createdNode
.getId(), createdNode.getTag(), createdNode.getLocationId(), createdNode.getName(),
createdNode.getCredentials().account, createdNode.getCredentials().key,
ipOrEmptyString(createdNode.getPublicAddresses())));
}
private void addNodeDetailsAsProjectProperties(CreateNodeResponse createdNode) {
private void addNodeDetailsAsProjectProperties(NodeMetadata createdNode) {
if (nodeElement.getIdproperty() != null)
getProject().setProperty(nodeElement.getIdproperty(), createdNode.getId());
if (nodeElement.getHostproperty() != null)
getProject().setProperty(nodeElement.getHostproperty(),
createdNode.getPublicAddresses().first().getHostAddress());
ipOrEmptyString(createdNode.getPublicAddresses()));
if (nodeElement.getKeyfile() != null && isKeyAuth(createdNode))
try {
Files.write(createdNode.getCredentials().key, new File(nodeElement.getKeyfile()),
@ -215,54 +229,49 @@ public class ComputeTask extends Task {
}
private void destroy(ComputeService computeService) {
log(String.format("destroy name: %s", nodeElement.getName()));
Iterable<? extends ComputeMetadata> nodesThatMatch = filterByName(computeService.listNodes(),
nodeElement.getName());
for (ComputeMetadata node : nodesThatMatch) {
log(String.format(" destroying id=%s, name=%s", node.getId(), node.getName()));
computeService.destroyNode(node);
}
log(String.format("destroy tag: %s", nodeElement.getTag()));
computeService.destroyNodes(nodeElement.getTag());
}
private void get(ComputeService computeService) {
log(String.format("get name: %s", nodeElement.getName()));
Iterable<? extends ComputeMetadata> nodesThatMatch = filterByName(computeService.listNodes(),
nodeElement.getName());
for (ComputeMetadata node : nodesThatMatch) {
log(String.format("get tag: %s", nodeElement.getTag()));
for (ComputeMetadata node : computeService.getNodes(nodeElement.getTag())) {
logDetails(computeService, 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
.format(
" node id=%s, name=%s, location=%s, state=%s, publicIp=%s, privateIp=%s, extra=%s",
metadata.getId(), node.getName(), node.getLocation(), metadata.getState(),
ipOrEmptyString(metadata.getPublicAddresses()), ipOrEmptyString(metadata
.getPrivateAddresses()), metadata.getExtra()));
" node id=%s, name=%s, tag=%s, location=%s, state=%s, publicIp=%s, privateIp=%s, extra=%s",
metadata.getId(), metadata.getName(), metadata.getTag(), metadata
.getLocationId(), metadata.getState(), ComputeTaskUtils
.ipOrEmptyString(metadata.getPublicAddresses()),
ipOrEmptyString(metadata.getPrivateAddresses()), metadata.getExtra()));
}
/**
* @return the configured {@link NodeElement} element
*/
public final NodeElement createNode() {
if (getNode() == null) {
public final NodeElement createNodes() {
if (getNodes() == null) {
this.nodeElement = new NodeElement();
}
return this.nodeElement;
}
public NodeElement getNode() {
public NodeElement getNodes() {
return this.nodeElement;
}
public String getAction() {
return action;
public String getActions() {
return actions;
}
public void setAction(String action) {
this.action = action;
public void setActions(String actions) {
this.actions = actions;
}
public NodeElement getNodeElement() {

View File

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

View File

@ -25,10 +25,11 @@ import java.io.File;
* @author Ivan Meredith
*/
public class NodeElement {
private String name;
private String tag;
private String size;
private String os;
private String image;
private int count = 1;
private String openports = "22";
private String passwordproperty;
private String keyfile;
@ -46,14 +47,6 @@ public class NodeElement {
this.location = location;
}
String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
String getUsernameproperty() {
return usernameproperty;
}
@ -153,4 +146,20 @@ public class NodeElement {
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.checkNotNull;
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 java.net.InetAddress;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.ComputeType;
import org.jclouds.compute.domain.CreateNodeResponse;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeSet;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.domain.internal.CreateNodeResponseImpl;
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.util.ComputeUtils;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.logging.Logger;
import org.jclouds.vcloud.VCloudClient;
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.options.InstantiateVAppTemplateOptions;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
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.util.concurrent.ListenableFuture;
import com.google.inject.Inject;
/**
@ -69,16 +78,33 @@ import com.google.inject.Inject;
*/
@Singleton
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
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
private final VCloudClient client;
protected final Provider<Set<? extends Image>> images;
protected final Provider<Set<? extends Size>> sizes;
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;
protected final ComputeUtils utils;
protected final Predicate<String> taskTester;
protected final Predicate<VApp> notFoundTester;
protected final ExecutorService executor;
protected static final Map<VAppStatus, NodeState> vAppStatusToNodeState = ImmutableMap
.<VAppStatus, NodeState> builder().put(VAppStatus.OFF, NodeState.TERMINATED).put(
@ -89,65 +115,92 @@ public class VCloudComputeService implements ComputeService, VCloudComputeClient
@Inject
public VCloudComputeService(VCloudClient client,
Provider<TemplateBuilder> templateBuilderProvider,
Provider<Set<? extends Image>> images, Provider<Set<? extends Size>> sizes,
ComputeUtils utils, Predicate<String> successTester,
@Named("NOT_FOUND") Predicate<VApp> notFoundTester) {
Provider<Map<String, ? extends Image>> images,
Provider<Map<String, ? extends Size>> sizes,
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.client = client;
this.images = images;
this.sizes = sizes;
this.locations = locations;
this.templateBuilderProvider = templateBuilderProvider;
this.utils = utils;
this.notFoundTester = notFoundTester;
this.executor = executor;
}
@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) {
checkNotNull(template.getImage().getLocation(), "location");
Map<String, String> metaMap = start(template.getImage().getLocation(), name, template
.getImage().getId(), template.getSize().getCores(), template.getSize().getRam(),
template.getSize().getDisk() * 1024 * 1024l, ImmutableMap.<String, String> of(),
options.getOpenPorts());
VApp vApp = client.getVApp(metaMap.get("id"));
CreateNodeResponse node = newCreateNodeResponse(template, metaMap, vApp);
if (options.getRunScript() != null) {
utils.runScriptOnNode(node, options.getRunScript());
public NodeSet runNodes(final String tag, int max, final Template template) {
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));
}
return node;
awaitCompletion(responses, executor, null, logger, "nodes");
return new NodeSetImpl(nodes);
}
protected CreateNodeResponse newCreateNodeResponse(Template template,
private void runVAppAndAddToSet(String name, String tag, Template template,
Set<NodeMetadata> nodes) {
Map<String, String> metaMap = start(template.getLocation().getId(), name, template.getImage()
.getId(), template.getSize().getCores(), template.getSize().getRam(), template
.getSize().getDisk() * 1024 * 1024l, ImmutableMap.<String, String> of(), template
.getOptions().getInboundPorts());
VApp vApp = client.getVApp(metaMap.get("id"));
NodeMetadata node = newCreateNodeResponse(tag, template, metaMap, vApp);
nodes.add(node);
if (template.getOptions().getRunScript() != null) {
utils.runScriptOnNode(node, template.getOptions().getRunScript());
}
}
protected NodeMetadata newCreateNodeResponse(String tag, Template template,
Map<String, String> metaMap, VApp vApp) {
return new CreateNodeResponseImpl(vApp.getId(), vApp.getName(), template.getImage()
.getLocation(), vApp.getLocation(), ImmutableMap.<String, String> of(),
vAppStatusToNodeState.get(vApp.getStatus()), getPublicAddresses(vApp.getId()),
getPrivateAddresses(vApp.getId()), new Credentials(metaMap.get("username"), metaMap
.get("password")), ImmutableMap.<String, String> of());
return new NodeMetadataImpl(vApp.getId(), vApp.getName(), template.getLocation().getId(),
vApp.getLocation(), ImmutableMap.<String, String> of(), tag, vAppStatusToNodeState
.get(vApp.getStatus()), getPublicAddresses(vApp.getId()),
getPrivateAddresses(vApp.getId()), ImmutableMap.<String, String> of(),
new Credentials(metaMap.get("username"), metaMap.get("password")));
}
@Override
public NodeMetadata getNodeMetadata(ComputeMetadata node) {
checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not "
+ node.getType());
return getNodeMetadataByIdInVDC(checkNotNull(node.getLocation(), "location"), checkNotNull(
return getNodeMetadataByIdInVDC(checkNotNull(node.getLocationId(), "location"), checkNotNull(
node.getId(), "node.id"));
}
protected NodeMetadata getNodeMetadataByIdInVDC(String vDCId, String id) {
VApp vApp = client.getVApp(id);
String tag = vApp.getName().replaceAll("-[0-9]+", "");
return new NodeMetadataImpl(vApp.getId(), vApp.getName(), vDCId, vApp.getLocation(),
ImmutableMap.<String, String> of(), vAppStatusToNodeState.get(vApp.getStatus()),
vApp.getNetworkToAddresses().values(), ImmutableSet.<InetAddress> of(), ImmutableMap
.<String, String> of());
ImmutableMap.<String, String> of(), tag,
vAppStatusToNodeState.get(vApp.getStatus()), vApp.getNetworkToAddresses().values(),
ImmutableSet.<InetAddress> of(), ImmutableMap.<String, String> of(), null);
}
@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();
for (NamedResource vdc : client.getDefaultOrganization().getVDCs().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
@ -172,12 +225,12 @@ public class VCloudComputeService implements ComputeService, VCloudComputeClient
}
@Override
public Set<? extends Size> listSizes() {
public Map<String, ? extends Size> getSizes() {
return sizes.get();
}
@Override
public Set<? extends Image> listImages() {
public Map<String, ? extends Image> getImages() {
return images.get();
}
@ -209,7 +262,7 @@ public class VCloudComputeService implements ComputeService, VCloudComputeClient
throw new TaskException("powerOn", vAppResponse, task);
}
logger.debug("<< on vApp(%s)", vAppResponse.getId());
Map<String, String> response = parseResponse(vAppResponse);
checkState(response.containsKey("id"), "bad configuration: [id] should be in response");
checkState(response.containsKey("username"),
@ -300,4 +353,53 @@ public class VCloudComputeService implements ComputeService, VCloudComputeClient
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;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
@ -32,6 +33,7 @@ import org.jclouds.Constants;
import org.jclouds.compute.ComputeService;
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.OsFamily;
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.reference.ComputeServiceConstants;
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.rest.RestContext;
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.NamedResource;
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.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.Injector;
@ -91,13 +100,6 @@ public class VCloudComputeServiceContextModule extends VCloudContextModule {
return new ComputeServiceContextImpl<VCloudAsyncClient, VCloudClient>(computeService, context);
}
@Provides
@Singleton
@ResourceLocation
String getVDC(VCloudClient client) {
return client.getDefaultVDC().getId();
}
protected static class LogHolder {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
@ -106,10 +108,12 @@ public class VCloudComputeServiceContextModule extends VCloudContextModule {
@Provides
@Singleton
protected Set<? extends Image> provideImages(final VCloudClient client,
final @ResourceLocation String vDC, LogHolder holder,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor)
throws InterruptedException, ExecutionException, TimeoutException {
protected Map<String, ? extends Image> provideImages(final VCloudClient client,
final Location vDC, LogHolder holder,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor,
Function<ComputeMetadata, String> indexer) throws InterruptedException,
ExecutionException, TimeoutException {
// TODO multi-VDC
final Set<Image> images = Sets.newHashSet();
holder.logger.debug(">> providing images");
Catalog response = client.getDefaultCatalog();
@ -132,8 +136,9 @@ public class VCloudComputeServiceContextModule extends VCloudContextModule {
Architecture arch = resource.getName().indexOf("64") == -1 ? Architecture.X86_32
: Architecture.X86_64;
VAppTemplate template = client.getVAppTemplate(item.getEntity().getId());
images.add(new ImageImpl(resource.getId(), template.getName(), "", myOs,
template.getName(), vDC, arch));
images.add(new ImageImpl(resource.getId(), template.getName(), vDC.getId(),
template.getLocation(), ImmutableMap.<String, String> of(), template
.getDescription(), "", myOs, template.getName(), arch));
return null;
}
}), executor));
@ -142,21 +147,60 @@ public class VCloudComputeServiceContextModule extends VCloudContextModule {
}
ConcurrentUtils.awaitCompletion(responses, executor, null, holder.logger, "images");
return images;
return Maps.uniqueIndex(images, indexer);
}
@Provides
@Singleton
protected Set<? extends Size> provideSizes(VCloudClient client, Set<? extends Image> images,
LogHolder holder, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor)
protected Function<ComputeMetadata, String> indexer() {
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 {
Set<Size> sizes = Sets.newHashSet();
for (int cpus : new int[] { 1, 2, 4 })
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,
ram, 10, ImmutableSet.<Architecture> of(Architecture.X86_32,
Architecture.X86_64)));
return sizes;
sizes.add(new SizeImpl(String.format("cpu=%d,ram=%s,disk=%d", cpus, ram, 10), null,
null, null, ImmutableMap.<String, String> of(), cpus, ram, 10, ImmutableSet
.<Architecture> of(Architecture.X86_32, Architecture.X86_64)));
return Maps.uniqueIndex(sizes, indexer);
}
}

View File

@ -29,12 +29,12 @@ import static org.testng.Assert.assertNotNull;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.PropertiesBuilder;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.RequiresHttp;
@ -139,7 +139,18 @@ public class VCloudLoginLiveTest {
context = new RestContextBuilder<VCloudLoginAsyncClient, 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) {

View File

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

View File

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

View File

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