mirror of https://github.com/apache/jclouds.git
normalized usage of null across compute apis, removed loop of recreating nodes, extracted BaseComputeService class
This commit is contained in:
parent
1a5016a4f8
commit
52e40c4651
|
@ -45,7 +45,6 @@ import org.jclouds.atmosonline.saas.functions.ReturnEndpointIfAlreadyExists;
|
|||
import org.jclouds.atmosonline.saas.options.ListOptions;
|
||||
import org.jclouds.blobstore.attr.ConsistencyModel;
|
||||
import org.jclouds.blobstore.attr.ConsistencyModels;
|
||||
import org.jclouds.blobstore.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.blobstore.functions.ThrowContainerNotFoundOn404;
|
||||
import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
|
||||
import org.jclouds.http.options.GetOptions;
|
||||
|
@ -57,8 +56,9 @@ import org.jclouds.rest.annotations.QueryParams;
|
|||
import org.jclouds.rest.annotations.RequestFilters;
|
||||
import org.jclouds.rest.annotations.ResponseParser;
|
||||
import org.jclouds.rest.annotations.SkipEncoding;
|
||||
import org.jclouds.rest.functions.ReturnFalseOnResourceNotFound;
|
||||
import org.jclouds.rest.functions.ReturnNullOnResourceNotFound;
|
||||
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
|
@ -136,7 +136,7 @@ public interface AtmosStorageAsyncClient {
|
|||
*/
|
||||
@GET
|
||||
@ResponseParser(ParseObjectFromHeadersAndHttpContent.class)
|
||||
@ExceptionParser(ReturnNullOnResourceNotFound.class)
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
@Path("/rest/namespace/{path}")
|
||||
@Consumes(MediaType.WILDCARD)
|
||||
ListenableFuture<AtmosObject> readFile(@PathParam("path") String path, GetOptions... options);
|
||||
|
@ -146,7 +146,7 @@ public interface AtmosStorageAsyncClient {
|
|||
*/
|
||||
@HEAD
|
||||
@ResponseParser(ParseObjectFromHeadersAndHttpContent.class)
|
||||
@ExceptionParser(ReturnNullOnResourceNotFound.class)
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
@Path("/rest/namespace/{path}")
|
||||
@Consumes(MediaType.WILDCARD)
|
||||
ListenableFuture<AtmosObject> headFile(@PathParam("path") String path);
|
||||
|
@ -156,7 +156,7 @@ public interface AtmosStorageAsyncClient {
|
|||
*/
|
||||
@HEAD
|
||||
@ResponseParser(ParseSystemMetadataFromHeaders.class)
|
||||
@ExceptionParser(ReturnNullOnResourceNotFound.class)
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
// currently throws 403 errors @QueryParams(keys = "metadata/system")
|
||||
@Path("/rest/namespace/{path}")
|
||||
@Consumes(MediaType.WILDCARD)
|
||||
|
@ -167,7 +167,7 @@ public interface AtmosStorageAsyncClient {
|
|||
*/
|
||||
@HEAD
|
||||
@ResponseParser(ParseSystemMetadataFromHeaders.class)
|
||||
@ExceptionParser(ReturnNullOnResourceNotFound.class)
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
@Path("/rest/namespace/{path}")
|
||||
@QueryParams(keys = "metadata/user")
|
||||
@Consumes(MediaType.WILDCARD)
|
||||
|
@ -186,7 +186,7 @@ public interface AtmosStorageAsyncClient {
|
|||
* @see AtmosStorageClient#pathExists
|
||||
*/
|
||||
@HEAD
|
||||
@ExceptionParser(ReturnFalseOnResourceNotFound.class)
|
||||
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||
@Path("/rest/namespace/{path}")
|
||||
@Consumes(MediaType.WILDCARD)
|
||||
ListenableFuture<Boolean> pathExists(@PathParam("path") String path);
|
||||
|
|
|
@ -39,7 +39,6 @@ import org.jclouds.atmosonline.saas.options.ListOptions;
|
|||
import org.jclouds.atmosonline.saas.reference.AtmosStorageConstants;
|
||||
import org.jclouds.blobstore.binders.BindBlobToMultipartFormTest;
|
||||
import org.jclouds.blobstore.config.BlobStoreObjectModule;
|
||||
import org.jclouds.blobstore.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.blobstore.functions.ThrowContainerNotFoundOn404;
|
||||
import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
|
||||
import org.jclouds.date.TimeStamp;
|
||||
|
@ -50,7 +49,8 @@ import org.jclouds.http.options.GetOptions;
|
|||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.logging.Logger.LoggerFactory;
|
||||
import org.jclouds.rest.RestClientTest;
|
||||
import org.jclouds.rest.functions.ReturnNullOnResourceNotFound;
|
||||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||
import org.jclouds.util.Jsr330;
|
||||
|
@ -221,7 +221,7 @@ public class AtmosStorageClientTest extends RestClientTest<AtmosStorageAsyncClie
|
|||
assertResponseParserClassEquals(method, httpMethod,
|
||||
ParseObjectFromHeadersAndHttpContent.class);
|
||||
assertSaxResponseParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnNullOnResourceNotFound.class);
|
||||
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(httpMethod);
|
||||
}
|
||||
|
@ -238,7 +238,7 @@ public class AtmosStorageClientTest extends RestClientTest<AtmosStorageAsyncClie
|
|||
|
||||
assertResponseParserClassEquals(method, httpMethod, ParseSystemMetadataFromHeaders.class);
|
||||
assertSaxResponseParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnNullOnResourceNotFound.class);
|
||||
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(httpMethod);
|
||||
}
|
||||
|
|
|
@ -21,14 +21,14 @@ 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 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 javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
|
@ -49,24 +49,19 @@ import org.jclouds.aws.ec2.domain.InstanceState;
|
|||
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.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.NodeSetImpl;
|
||||
import org.jclouds.compute.internal.BaseComputeService;
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.compute.util.ComputeUtils;
|
||||
import static 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;
|
||||
|
@ -81,7 +76,7 @@ import com.google.inject.internal.ImmutableSet;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class EC2ComputeService implements ComputeService {
|
||||
public class EC2ComputeService extends BaseComputeService {
|
||||
|
||||
private static Function<RunningInstance, String> instanceToId = new Function<RunningInstance, String>() {
|
||||
@Override
|
||||
|
@ -89,70 +84,42 @@ public class EC2ComputeService implements ComputeService {
|
|||
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) && from.getState() != NodeState.TERMINATED;
|
||||
}
|
||||
|
||||
public NodeMatchesTag(String tag) {
|
||||
super();
|
||||
this.tag = tag;
|
||||
}
|
||||
};
|
||||
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
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;
|
||||
protected final Predicate<RunningInstance> instanceStateRunning;
|
||||
protected final Predicate<RunningInstance> instanceStateTerminated;
|
||||
protected final RunningInstanceToNodeMetadata runningInstanceToNodeMetadata;
|
||||
protected final ExecutorService executor;
|
||||
protected final ComputeUtils utils;
|
||||
|
||||
@Inject
|
||||
public EC2ComputeService(EC2Client client, Provider<TemplateBuilder> templateBuilderProvider,
|
||||
Provider<Map<String, ? extends Image>> images,
|
||||
EC2ComputeService(Provider<Map<String, ? extends Image>> images,
|
||||
Provider<Map<String, ? extends Size>> sizes,
|
||||
Provider<Map<String, ? extends Location>> locations,
|
||||
Map<RegionTag, KeyPairCredentials> credentialsMap,
|
||||
Provider<TemplateBuilder> templateBuilderProvider, String nodeNamingConvention,
|
||||
ComputeUtils utils, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor,
|
||||
EC2Client ec2Client, Map<RegionTag, KeyPairCredentials> credentialsMap,
|
||||
Map<PortsRegionTag, String> securityGroupMap,
|
||||
CreateKeyPairIfNeeded createKeyPairIfNeeded,
|
||||
CreateSecurityGroupIfNeeded createSecurityGroupIfNeeded, ComputeUtils utils,
|
||||
CreateSecurityGroupIfNeeded createSecurityGroupIfNeeded,
|
||||
@Named("RUNNING") Predicate<RunningInstance> instanceStateRunning,
|
||||
@Named("TERMINATED") Predicate<RunningInstance> instanceStateTerminated,
|
||||
RunningInstanceToNodeMetadata runningInstanceToNodeMetadata,
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
|
||||
this.templateBuilderProvider = templateBuilderProvider;
|
||||
this.ec2Client = client;
|
||||
this.images = images;
|
||||
this.utils = utils;
|
||||
this.sizes = sizes;
|
||||
this.locations = locations;
|
||||
RunningInstanceToNodeMetadata runningInstanceToNodeMetadata) {
|
||||
super(images, sizes, locations, templateBuilderProvider, nodeNamingConvention, utils,
|
||||
executor);
|
||||
this.ec2Client = ec2Client;
|
||||
this.credentialsMap = credentialsMap;
|
||||
this.securityGroupMap = securityGroupMap;
|
||||
this.createKeyPairIfNeeded = createKeyPairIfNeeded;
|
||||
this.createSecurityGroupIfNeeded = createSecurityGroupIfNeeded;
|
||||
this.securityGroupMap = securityGroupMap;
|
||||
this.instanceStateRunning = instanceStateRunning;
|
||||
this.instanceStateTerminated = instanceStateTerminated;
|
||||
this.runningInstanceToNodeMetadata = runningInstanceToNodeMetadata;
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeSet runNodesWithTag(String tag, int count, final Template template) {
|
||||
public Map<String, NodeMetadata> runNodesWithTag(String tag, int count, final 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());
|
||||
|
@ -224,7 +191,7 @@ public class EC2ComputeService implements ComputeService {
|
|||
}
|
||||
nodesToStart = awaitCompletion(responses, executor, null, logger, "nodes").size();
|
||||
}
|
||||
return new NodeSetImpl(nodes);
|
||||
return Maps.uniqueIndex(nodes, METADATA_TO_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -243,29 +210,18 @@ public class EC2ComputeService implements ComputeService {
|
|||
.concat(ec2Client.getInstanceServices().describeInstancesInRegion(region, id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, NodeMetadata> getNodes() {
|
||||
logger.debug(">> listing servers");
|
||||
Map<String, NodeMetadata> nodes = doGetNodes();
|
||||
logger.debug("<< list(%d)", nodes.size());
|
||||
return nodes;
|
||||
}
|
||||
|
||||
protected Map<String, NodeMetadata> doGetNodes() {
|
||||
protected Iterable<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(nodes, Iterables.transform(Iterables.concat(ec2Client
|
||||
.getInstanceServices().describeInstancesInRegion(region)),
|
||||
runningInstanceToNodeMetadata));
|
||||
}
|
||||
return Maps.uniqueIndex(nodes, METADATA_TO_ID);
|
||||
return nodes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyNode(ComputeMetadata metadata) {
|
||||
checkArgument(metadata.getType() == ComputeType.NODE, "this is only valid for nodes, not "
|
||||
+ metadata.getType());
|
||||
checkNotNull(metadata.getId(), "node.id");
|
||||
protected boolean doDestroyNode(ComputeMetadata metadata) {
|
||||
NodeMetadata node = metadata instanceof NodeMetadata ? NodeMetadata.class.cast(metadata)
|
||||
: getNodeMetadata(metadata);
|
||||
String tag = checkNotNull(node.getTag(), "node.tag");
|
||||
|
@ -282,7 +238,7 @@ public class EC2ComputeService implements ComputeService {
|
|||
}
|
||||
logger.debug("<< terminated instance(%s) success(%s)", node.getId(), success);
|
||||
}
|
||||
if (Iterables.all(doGetNodes(tag), new Predicate<NodeMetadata>() {
|
||||
if (Iterables.all(doGetNodes(tag).values(), new Predicate<NodeMetadata>() {
|
||||
@Override
|
||||
public boolean apply(NodeMetadata input) {
|
||||
return input.getState() == NodeState.TERMINATED;
|
||||
|
@ -291,6 +247,7 @@ public class EC2ComputeService implements ComputeService {
|
|||
deleteKeyPair(region, tag);
|
||||
deleteSecurityGroup(region, tag);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private RunningInstance getInstance(NodeMetadata node, Region region) {
|
||||
|
@ -324,60 +281,8 @@ public class EC2ComputeService implements ComputeService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void destroyNodesWithTag(String tag) { // TODO parallel
|
||||
logger.debug(">> terminating servers by tag(%s)", tag);
|
||||
Iterable<NodeMetadata> nodesToDestroy = Iterables.filter(doGetNodes(tag),
|
||||
new Predicate<NodeMetadata>() {
|
||||
@Override
|
||||
public boolean apply(NodeMetadata input) {
|
||||
return input.getState() != NodeState.TERMINATED;
|
||||
|
||||
}
|
||||
});
|
||||
Map<NodeMetadata, ListenableFuture<Void>> responses = Maps.newHashMap();
|
||||
for (final NodeMetadata node : nodesToDestroy) {
|
||||
responses.put(node, 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 getNodesWithTag(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 Map<String, ? extends Image> getImages() {
|
||||
return images.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemplateBuilder templateBuilder() {
|
||||
return templateBuilderProvider.get();
|
||||
protected NodeMetadata startNode(String tag, String name, Template template) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
|
@ -67,7 +67,6 @@ import org.jclouds.blobstore.attr.ConsistencyModels;
|
|||
import org.jclouds.blobstore.functions.ReturnFalseOnContainerNotFound;
|
||||
import org.jclouds.blobstore.functions.ReturnFalseOnKeyNotFound;
|
||||
import org.jclouds.blobstore.functions.ReturnNullOnKeyNotFound;
|
||||
import org.jclouds.blobstore.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.blobstore.functions.ThrowContainerNotFoundOn404;
|
||||
import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
|
||||
import org.jclouds.http.functions.ParseETagHeader;
|
||||
|
@ -84,6 +83,7 @@ import org.jclouds.rest.annotations.ResponseParser;
|
|||
import org.jclouds.rest.annotations.SkipEncoding;
|
||||
import org.jclouds.rest.annotations.VirtualHost;
|
||||
import org.jclouds.rest.annotations.XMLResponseParser;
|
||||
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
|
|
|
@ -58,7 +58,6 @@ import org.jclouds.blobstore.config.BlobStoreObjectModule;
|
|||
import org.jclouds.blobstore.functions.ReturnFalseOnContainerNotFound;
|
||||
import org.jclouds.blobstore.functions.ReturnFalseOnKeyNotFound;
|
||||
import org.jclouds.blobstore.functions.ReturnNullOnKeyNotFound;
|
||||
import org.jclouds.blobstore.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.blobstore.functions.ThrowContainerNotFoundOn404;
|
||||
import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
|
||||
import org.jclouds.blobstore.reference.BlobStoreConstants;
|
||||
|
@ -71,6 +70,7 @@ import org.jclouds.http.options.GetOptions;
|
|||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.logging.Logger.LoggerFactory;
|
||||
import org.jclouds.rest.RestClientTest;
|
||||
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||
import org.jclouds.util.Jsr330;
|
||||
|
|
|
@ -53,7 +53,6 @@ import org.jclouds.blobstore.functions.ReturnFalseOnContainerNotFound;
|
|||
import org.jclouds.blobstore.functions.ReturnFalseOnKeyNotFound;
|
||||
import org.jclouds.blobstore.functions.ReturnNullOnContainerNotFound;
|
||||
import org.jclouds.blobstore.functions.ReturnNullOnKeyNotFound;
|
||||
import org.jclouds.blobstore.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.http.functions.ParseETagHeader;
|
||||
import org.jclouds.http.functions.ReturnTrueOn404;
|
||||
import org.jclouds.http.options.GetOptions;
|
||||
|
@ -67,6 +66,7 @@ import org.jclouds.rest.annotations.RequestFilters;
|
|||
import org.jclouds.rest.annotations.ResponseParser;
|
||||
import org.jclouds.rest.annotations.SkipEncoding;
|
||||
import org.jclouds.rest.annotations.XMLResponseParser;
|
||||
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
|
|
|
@ -41,7 +41,6 @@ import org.jclouds.azure.storage.config.AzureStorageRestClientModule;
|
|||
import org.jclouds.azure.storage.options.ListOptions;
|
||||
import org.jclouds.azure.storage.reference.AzureStorageConstants;
|
||||
import org.jclouds.blobstore.functions.ReturnNullOnContainerNotFound;
|
||||
import org.jclouds.blobstore.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.concurrent.config.ExecutorServiceModule;
|
||||
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
|
||||
import org.jclouds.http.functions.CloseContentAndReturn;
|
||||
|
@ -52,6 +51,7 @@ import org.jclouds.logging.Logger;
|
|||
import org.jclouds.logging.Logger.LoggerFactory;
|
||||
import org.jclouds.rest.config.RestModule;
|
||||
import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions;
|
||||
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||
import org.jclouds.util.Jsr330;
|
||||
|
|
|
@ -23,7 +23,6 @@ import java.util.Map;
|
|||
import org.jclouds.compute.domain.ComputeMetadata;
|
||||
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;
|
||||
|
@ -105,7 +104,7 @@ public interface ComputeService {
|
|||
* - how to configure the nodes
|
||||
* @return all of the nodes the api was able to launch in a running state.
|
||||
*/
|
||||
NodeSet runNodesWithTag(String tag, int count, Template template);
|
||||
Map<String, ? extends NodeMetadata> runNodesWithTag(String tag, int count, Template template);
|
||||
|
||||
/**
|
||||
* destroy the node. If it is the only node in a tag set, the dependent resources will also be
|
||||
|
@ -130,6 +129,6 @@ public interface ComputeService {
|
|||
*
|
||||
* @param tag
|
||||
*/
|
||||
NodeSet getNodesWithTag(String tag);
|
||||
Map<String, ? extends NodeMetadata> getNodesWithTag(String tag);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,28 +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;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public interface NodeSet extends Set<NodeMetadata> {
|
||||
|
||||
}
|
|
@ -124,11 +124,8 @@ public class NodeMetadataImpl extends ComputeMetadataImpl implements NodeMetadat
|
|||
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;
|
||||
}
|
||||
|
@ -142,16 +139,6 @@ 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;
|
||||
} else if (!extra.equals(other.extra))
|
||||
return false;
|
||||
if (privateAddresses == null) {
|
||||
if (other.privateAddresses != null)
|
||||
return false;
|
||||
|
@ -162,11 +149,6 @@ public class NodeMetadataImpl extends ComputeMetadataImpl implements NodeMetadat
|
|||
return false;
|
||||
} else if (!publicAddresses.equals(other.publicAddresses))
|
||||
return false;
|
||||
if (state == null) {
|
||||
if (other.state != null)
|
||||
return false;
|
||||
} else if (!state.equals(other.state))
|
||||
return false;
|
||||
if (tag == null) {
|
||||
if (other.tag != null)
|
||||
return false;
|
||||
|
|
|
@ -1,40 +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.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);
|
||||
}
|
||||
|
||||
}
|
|
@ -126,7 +126,8 @@ public class TemplateImpl implements Template {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TemplateImpl [image=" + image + ", size=" + size + "]";
|
||||
return "[location=" + location + ", image=" + image + ", size=" + size + ", options="
|
||||
+ options + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,280 @@
|
|||
/**
|
||||
*
|
||||
* 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.compute.internal;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.jclouds.concurrent.ConcurrentUtils.awaitCompletion;
|
||||
import static org.jclouds.concurrent.ConcurrentUtils.makeListenable;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
|
||||
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.Image;
|
||||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
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.reference.ComputeServiceConstants;
|
||||
import org.jclouds.compute.util.ComputeUtils;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.logging.Logger;
|
||||
|
||||
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
|
||||
*/
|
||||
public abstract class BaseComputeService implements ComputeService {
|
||||
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
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 String nodeNamingConvention;
|
||||
protected final ComputeUtils utils;
|
||||
protected final ExecutorService executor;
|
||||
|
||||
private static class NodeMatchesTag implements Predicate<NodeMetadata> {
|
||||
private final String tag;
|
||||
|
||||
public NodeMatchesTag(String tag) {
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(NodeMetadata from) {
|
||||
return from.getTag().equals(tag);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
public static Function<ComputeMetadata, String> METADATA_TO_ID = new Function<ComputeMetadata, String>() {
|
||||
@Override
|
||||
public String apply(ComputeMetadata from) {
|
||||
return from.getId();
|
||||
}
|
||||
};
|
||||
|
||||
public static Function<ComputeMetadata, String> METADATA_TO_NAME = new Function<ComputeMetadata, String>() {
|
||||
@Override
|
||||
public String apply(ComputeMetadata from) {
|
||||
return from.getName();
|
||||
}
|
||||
};
|
||||
|
||||
protected BaseComputeService(Provider<Map<String, ? extends Image>> images,
|
||||
Provider<Map<String, ? extends Size>> sizes,
|
||||
Provider<Map<String, ? extends Location>> locations,
|
||||
Provider<TemplateBuilder> templateBuilderProvider, String nodeNamingConvention,
|
||||
ComputeUtils utils, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
|
||||
this.images = images;
|
||||
this.sizes = sizes;
|
||||
this.locations = locations;
|
||||
this.templateBuilderProvider = templateBuilderProvider;
|
||||
this.nodeNamingConvention = nodeNamingConvention;
|
||||
this.utils = utils;
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends NodeMetadata> runNodesWithTag(final String tag, int count,
|
||||
final Template template) {
|
||||
checkArgument(tag.indexOf('-') == -1, "tag cannot contain hyphens");
|
||||
checkNotNull(template.getLocation(), "location");
|
||||
final Set<NodeMetadata> nodes = Sets.newHashSet();
|
||||
logger.debug(">> running %d node%s tag(%s) location(%s) image(%s) size(%s) options(%s)",
|
||||
count, count > 1 ? "s" : "", tag, template.getLocation().getId(), template
|
||||
.getImage().getId(), template.getSize().getId(), template.getOptions());
|
||||
|
||||
Map<String, ListenableFuture<Void>> responses = Maps.newHashMap();
|
||||
for (final String name : getNextNames(tag, count)) {
|
||||
responses.put(name, makeListenable(executor.submit(new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
NodeMetadata node = null;
|
||||
logger.debug(">> starting node(%s) tag(%s)", name, tag);
|
||||
node = startNode(tag, name, template);
|
||||
logger.debug("<< running node(%s)", node.getId());
|
||||
try {
|
||||
utils.runOptionsOnNode(node, template.getOptions());
|
||||
logger.debug("<< options applied node(%s)", node.getId());
|
||||
nodes.add(node);
|
||||
} catch (Exception e) {
|
||||
if (!template.getOptions().shouldDestroyOnError())
|
||||
nodes.add(node);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}), executor));
|
||||
}
|
||||
Map<String, Exception> exceptions = awaitCompletion(responses, executor, null, logger,
|
||||
"starting nodes");
|
||||
if (exceptions.size() > 0 && template.getOptions().shouldDestroyOnError()) {
|
||||
ImmutableMap<String, ? extends ComputeMetadata> currentNodes = Maps.uniqueIndex(doGetNodes(),
|
||||
METADATA_TO_ID);
|
||||
for (Entry<String, Exception> entry : exceptions.entrySet()) {
|
||||
logger.error(entry.getValue(), "<< error applying nodes(%s) [%s] destroying ", entry
|
||||
.getKey(), entry.getValue().getMessage());
|
||||
destroyNode(currentNodes.get(entry.getKey()));
|
||||
}
|
||||
}
|
||||
return Maps.uniqueIndex(nodes, METADATA_TO_ID);
|
||||
}
|
||||
|
||||
protected Set<String> getNextNames(final String tag, int count) {
|
||||
Set<String> names = Sets.newHashSet();
|
||||
int nodeIndex = new SecureRandom().nextInt(8096);
|
||||
Iterable<? extends ComputeMetadata> allNodes = doGetNodes();
|
||||
Map<String, ? extends ComputeMetadata> currentNodes = Maps.uniqueIndex(allNodes, METADATA_TO_NAME);
|
||||
while (names.size() < count) {
|
||||
String name = String.format(nodeNamingConvention, tag, nodeIndex++);
|
||||
if (!currentNodes.containsKey(name)) {
|
||||
names.add(name);
|
||||
}
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
protected abstract NodeMetadata startNode(String tag, String name, Template template);
|
||||
|
||||
protected abstract boolean doDestroyNode(ComputeMetadata node);
|
||||
|
||||
protected abstract Iterable<? extends ComputeMetadata> doGetNodes();
|
||||
|
||||
@Override
|
||||
public void destroyNodesWithTag(String tag) { // TODO parallel
|
||||
logger.debug(">> terminating nodes by tag(%s)", tag);
|
||||
Iterable<? extends NodeMetadata> nodesToDestroy = Iterables.filter(doGetNodes(tag).values(),
|
||||
new Predicate<NodeMetadata>() {
|
||||
@Override
|
||||
public boolean apply(NodeMetadata input) {
|
||||
return input.getState() != NodeState.TERMINATED;
|
||||
|
||||
}
|
||||
});
|
||||
Map<NodeMetadata, ListenableFuture<Void>> responses = Maps.newHashMap();
|
||||
for (final NodeMetadata node : nodesToDestroy) {
|
||||
responses.put(node, makeListenable(executor.submit(new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
destroyNode(node);
|
||||
return null;
|
||||
}
|
||||
}), executor));
|
||||
}
|
||||
awaitCompletion(responses, executor, null, logger, "destroying nodes");
|
||||
logger.debug("<< destroyed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends Location> getLocations() {
|
||||
return locations.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends ComputeMetadata> getNodes() {
|
||||
logger.debug(">> listing servers");
|
||||
ImmutableMap<String, ? extends ComputeMetadata> map = Maps.uniqueIndex(doGetNodes(), METADATA_TO_ID);
|
||||
logger.debug("<< list(%d)", map.size());
|
||||
return map;
|
||||
}
|
||||
|
||||
@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");
|
||||
logger.debug(">> deleting node(%s)", node.getId());
|
||||
boolean successful = doDestroyNode(node);
|
||||
logger.debug("<< deleted node(%s) success(%s)", node.getId(), successful);
|
||||
}
|
||||
|
||||
protected Map<String, ? extends NodeMetadata> doGetNodes(final String tag) {
|
||||
Iterable<? extends NodeMetadata> nodes = Iterables.filter(Iterables.transform(doGetNodes(),
|
||||
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 Maps.uniqueIndex(Iterables.filter(nodes, new NodeMatchesTag(tag)), METADATA_TO_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends NodeMetadata> getNodesWithTag(String tag) {
|
||||
logger.debug(">> listing nodes by tag(%s)", tag);
|
||||
Map<String, ? extends NodeMetadata> nodes = doGetNodes(tag);
|
||||
logger.debug("<< list(%d)", nodes.size());
|
||||
return nodes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends Size> getSizes() {
|
||||
return sizes.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends Image> getImages() {
|
||||
return images.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemplateBuilder templateBuilder() {
|
||||
return templateBuilderProvider.get();
|
||||
}
|
||||
|
||||
}
|
|
@ -3,6 +3,8 @@ package org.jclouds.compute.options;
|
|||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Contains options supported in the {@code ComputeService#runNode} operation. <h2>
|
||||
* Usage</h2> The recommended way to instantiate a TemplateOptions object is to statically import
|
||||
|
@ -30,6 +32,8 @@ public class TemplateOptions {
|
|||
|
||||
private String publicKey;
|
||||
|
||||
private boolean destroyOnError;
|
||||
|
||||
public int[] getInboundPorts() {
|
||||
return inboundPorts;
|
||||
}
|
||||
|
@ -46,6 +50,18 @@ public class TemplateOptions {
|
|||
return publicKey;
|
||||
}
|
||||
|
||||
public boolean shouldDestroyOnError() {
|
||||
return destroyOnError;
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is an error applying options after creating the node, destroy it.
|
||||
*/
|
||||
public TemplateOptions destroyOnError() {
|
||||
this.destroyOnError = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This script will be executed as the root user upon system startup.
|
||||
*/
|
||||
|
@ -86,6 +102,13 @@ public class TemplateOptions {
|
|||
}
|
||||
|
||||
public static class Builder {
|
||||
/**
|
||||
* @see TemplateOptions#destroyOnError
|
||||
*/
|
||||
public static TemplateOptions destroyOnError() {
|
||||
TemplateOptions options = new TemplateOptions();
|
||||
return options.destroyOnError();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TemplateOptions#inboundPorts
|
||||
|
@ -120,4 +143,11 @@ public class TemplateOptions {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TemplateOptions [inboundPorts=" + Arrays.toString(inboundPorts) + ", privateKey="
|
||||
+ (privateKey != null) + ", publicKey=" + (publicKey != null) + ", runScript="
|
||||
+ (script != null) + ", destroyOnError=" + destroyOnError + "]";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,6 @@ import org.jclouds.scriptbuilder.domain.OsFamily;
|
|||
import org.jclouds.ssh.ExecResponse;
|
||||
import org.jclouds.ssh.SshClient;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Throwables;
|
||||
|
@ -73,13 +72,6 @@ public class ComputeUtils {
|
|||
private final Predicate<InetSocketAddress> socketTester;
|
||||
private final ExecutorService executor;
|
||||
|
||||
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,
|
||||
@Named("NOT_RUNNING") Predicate<SshClient> runScriptNotRunning,
|
||||
|
@ -113,7 +105,6 @@ public class ComputeUtils {
|
|||
if (options.getRunScript() != null) {
|
||||
callables.add(runScriptOnNode(node, "runscript.sh", options.getRunScript()));
|
||||
}
|
||||
|
||||
if (options.getPublicKey() != null) {
|
||||
callables.add(authorizeKeyOnNode(node, options.getPublicKey()));
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.io.IOException;
|
|||
import java.net.InetSocketAddress;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
@ -37,7 +38,6 @@ import org.jclouds.compute.domain.ComputeMetadata;
|
|||
import org.jclouds.compute.domain.ComputeType;
|
||||
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;
|
||||
|
@ -79,8 +79,8 @@ public abstract class BaseComputeServiceLiveTest {
|
|||
protected SshClient.Factory sshFactory;
|
||||
protected String tag;
|
||||
|
||||
private RetryablePredicate<InetSocketAddress> socketTester;
|
||||
private SortedSet<NodeMetadata> nodes;
|
||||
protected RetryablePredicate<InetSocketAddress> socketTester;
|
||||
protected SortedSet<NodeMetadata> nodes;
|
||||
protected ComputeServiceContext context;
|
||||
protected ComputeService client;
|
||||
protected String user;
|
||||
|
@ -145,8 +145,22 @@ public abstract class BaseComputeServiceLiveTest {
|
|||
.append("wget -qO/usr/bin/runurl run.alestic.com/runurl\n")//
|
||||
.append("chmod 755 /usr/bin/runurl\n")//
|
||||
.toString().getBytes());
|
||||
nodes = Sets.newTreeSet(client.runNodesWithTag(tag, 2, template));
|
||||
nodes = Sets.newTreeSet(client.runNodesWithTag(tag, 2, template).values());
|
||||
assertEquals(nodes.size(), 2);
|
||||
checkNodes();
|
||||
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());
|
||||
|
||||
// run one more
|
||||
nodes.addAll(client.runNodesWithTag(tag, 1, template).values());
|
||||
assertEquals(nodes.size(), 3);
|
||||
checkNodes();
|
||||
}
|
||||
|
||||
private void checkNodes() throws IOException {
|
||||
for (NodeMetadata node : nodes) {
|
||||
assertNotNull(node.getId());
|
||||
assertNotNull(node.getTag());
|
||||
|
@ -160,19 +174,14 @@ public abstract class BaseComputeServiceLiveTest {
|
|||
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 {
|
||||
NodeSet metadataSet = client.getNodesWithTag(tag);
|
||||
Set<? extends NodeMetadata> metadataSet = Sets.newHashSet(client.getNodesWithTag(tag)
|
||||
.values());
|
||||
for (NodeMetadata node : nodes) {
|
||||
metadataSet.remove(node);
|
||||
NodeMetadata metadata = client.getNodeMetadata(node);
|
||||
|
@ -267,7 +276,7 @@ public abstract class BaseComputeServiceLiveTest {
|
|||
protected void cleanup() throws InterruptedException, ExecutionException, TimeoutException {
|
||||
if (nodes != null) {
|
||||
client.destroyNodesWithTag(tag);
|
||||
for (NodeMetadata node : client.getNodesWithTag(tag)) {
|
||||
for (NodeMetadata node : client.getNodesWithTag(tag).values()) {
|
||||
assert node.getState() == NodeState.TERMINATED : node;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,16 +25,18 @@ import javax.inject.Singleton;
|
|||
import org.jclouds.http.HttpResponseException;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
@Singleton
|
||||
public class ReturnTrueOn404 implements Function<Exception, Boolean> {
|
||||
|
||||
public Boolean apply(Exception from) {
|
||||
if (from instanceof HttpResponseException) {
|
||||
HttpResponseException responseException = (HttpResponseException) from;
|
||||
if (responseException.getResponse().getStatusCode() == 404) {
|
||||
return true;
|
||||
}
|
||||
Iterable<HttpResponseException> throwables = Iterables.filter(
|
||||
Throwables.getCausalChain(from), HttpResponseException.class);
|
||||
if (Iterables.size(throwables) >= 1
|
||||
&& Iterables.get(throwables, 0).getResponse().getStatusCode() == 404) {
|
||||
return true;
|
||||
}
|
||||
return Boolean.class.cast(propagateOrNull(from));
|
||||
}
|
||||
|
|
|
@ -18,12 +18,13 @@
|
|||
*/
|
||||
package org.jclouds.rest.functions;
|
||||
|
||||
import static org.jclouds.util.Utils.propagateOrNull;
|
||||
|
||||
import java.util.List;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.http.functions.ReturnTrueOn404;
|
||||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
@ -35,13 +36,23 @@ import com.google.common.collect.Iterables;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class ReturnFalseOnResourceNotFound implements Function<Exception, Boolean> {
|
||||
public class ReturnFalseOnNotFoundOr404 implements Function<Exception, Boolean> {
|
||||
|
||||
private final ReturnTrueOn404 rto404;
|
||||
|
||||
@Inject
|
||||
private ReturnFalseOnNotFoundOr404(ReturnTrueOn404 rto404) {
|
||||
this.rto404 = checkNotNull(rto404, "rto404");
|
||||
}
|
||||
|
||||
public Boolean apply(Exception from) {
|
||||
List<Throwable> throwables = Throwables.getCausalChain(from);
|
||||
Iterable<HttpResponseException> throwables = Iterables.filter(
|
||||
Throwables.getCausalChain(from), HttpResponseException.class);
|
||||
if (Iterables.size(Iterables.filter(throwables, ResourceNotFoundException.class)) >= 1) {
|
||||
return false;
|
||||
} else {
|
||||
return !rto404.apply(from);
|
||||
}
|
||||
return Boolean.class.cast(propagateOrNull(from));
|
||||
}
|
||||
|
||||
}
|
|
@ -18,25 +18,42 @@
|
|||
*/
|
||||
package org.jclouds.rest.functions;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.jclouds.util.Utils.propagateOrNull;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.http.functions.ReturnTrueOn404;
|
||||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class ReturnNullOnResourceNotFound implements Function<Exception, Object> {
|
||||
public class ReturnNullOnNotFoundOr404 implements Function<Exception, Object> {
|
||||
private final ReturnTrueOn404 rto404;
|
||||
|
||||
@Inject
|
||||
private ReturnNullOnNotFoundOr404(ReturnTrueOn404 rto404) {
|
||||
this.rto404 = checkNotNull(rto404, "rto404");
|
||||
}
|
||||
|
||||
public Object apply(Exception from) {
|
||||
if (from instanceof ResourceNotFoundException) {
|
||||
Iterable<HttpResponseException> throwables = Iterables.filter(
|
||||
Throwables.getCausalChain(from), HttpResponseException.class);
|
||||
if (Iterables.size(Iterables.filter(throwables, ResourceNotFoundException.class)) >= 1) {
|
||||
return null;
|
||||
} else if (rto404.apply(from)) {
|
||||
return null;
|
||||
}
|
||||
return propagateOrNull(from);
|
||||
return Object.class.cast(propagateOrNull(from));
|
||||
}
|
||||
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.blobstore.functions;
|
||||
package org.jclouds.rest.functions;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.jclouds.util.Utils.propagateOrNull;
|
||||
|
@ -24,11 +24,18 @@ import static org.jclouds.util.Utils.propagateOrNull;
|
|||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.http.functions.ReturnTrueOn404;
|
||||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class ReturnVoidOnNotFoundOr404 implements Function<Exception, Void> {
|
||||
|
||||
|
@ -40,7 +47,9 @@ public class ReturnVoidOnNotFoundOr404 implements Function<Exception, Void> {
|
|||
}
|
||||
|
||||
public Void apply(Exception from) {
|
||||
if (from instanceof ResourceNotFoundException) {
|
||||
Iterable<HttpResponseException> throwables = Iterables.filter(
|
||||
Throwables.getCausalChain(from), HttpResponseException.class);
|
||||
if (Iterables.size(Iterables.filter(throwables, ResourceNotFoundException.class)) >= 1) {
|
||||
return null;
|
||||
} else {
|
||||
Boolean value = rto404.apply(from);
|
|
@ -30,7 +30,6 @@ import javax.ws.rs.Path;
|
|||
import javax.ws.rs.PathParam;
|
||||
|
||||
import org.jclouds.blobstore.functions.ReturnNullOnKeyNotFound;
|
||||
import org.jclouds.blobstore.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.http.filters.BasicAuthentication;
|
||||
import org.jclouds.mezeo.pcs2.binders.BindContainerNameToXmlPayload;
|
||||
import org.jclouds.mezeo.pcs2.binders.BindDataToPayload;
|
||||
|
@ -54,6 +53,7 @@ import org.jclouds.rest.annotations.ResponseParser;
|
|||
import org.jclouds.rest.annotations.SkipEncoding;
|
||||
import org.jclouds.rest.annotations.XMLResponseParser;
|
||||
import org.jclouds.rest.binders.BindToStringPayload;
|
||||
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@ import javax.ws.rs.core.HttpHeaders;
|
|||
import org.jclouds.blobstore.binders.BindBlobToMultipartFormTest;
|
||||
import org.jclouds.blobstore.config.BlobStoreObjectModule;
|
||||
import org.jclouds.blobstore.functions.ReturnNullOnKeyNotFound;
|
||||
import org.jclouds.blobstore.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.encryption.EncryptionService;
|
||||
import org.jclouds.http.filters.BasicAuthentication;
|
||||
import org.jclouds.http.functions.CloseContentAndReturn;
|
||||
|
@ -54,6 +53,7 @@ import org.jclouds.mezeo.pcs2.xml.ContainerHandler;
|
|||
import org.jclouds.mezeo.pcs2.xml.FileHandler;
|
||||
import org.jclouds.rest.RestClientTest;
|
||||
import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions;
|
||||
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
|
|
|
@ -39,7 +39,6 @@ import org.jclouds.blobstore.domain.PageSet;
|
|||
import org.jclouds.blobstore.functions.ReturnFalseOnContainerNotFound;
|
||||
import org.jclouds.blobstore.functions.ReturnFalseOnKeyNotFound;
|
||||
import org.jclouds.blobstore.functions.ReturnNullOnKeyNotFound;
|
||||
import org.jclouds.blobstore.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.blobstore.functions.ThrowContainerNotFoundOn404;
|
||||
import org.jclouds.http.functions.ParseETagHeader;
|
||||
import org.jclouds.http.options.GetOptions;
|
||||
|
@ -75,6 +74,7 @@ import org.jclouds.rest.annotations.QueryParams;
|
|||
import org.jclouds.rest.annotations.RequestFilters;
|
||||
import org.jclouds.rest.annotations.ResponseParser;
|
||||
import org.jclouds.rest.annotations.SkipEncoding;
|
||||
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
|
|
|
@ -75,6 +75,9 @@ import org.jclouds.rest.annotations.QueryParams;
|
|||
import org.jclouds.rest.annotations.RequestFilters;
|
||||
import org.jclouds.rest.annotations.ResponseParser;
|
||||
import org.jclouds.rest.annotations.SkipEncoding;
|
||||
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
|
@ -109,6 +112,7 @@ public interface CloudServersAsyncClient {
|
|||
@GET
|
||||
@ResponseParser(ParseServerFromJsonResponse.class)
|
||||
@QueryParams(keys = "format", values = "json")
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
@Path("/servers/{id}")
|
||||
ListenableFuture<Server> getServer(@PathParam("id") int id);
|
||||
|
||||
|
@ -116,7 +120,7 @@ public interface CloudServersAsyncClient {
|
|||
* @see CloudServersClient#deleteServer
|
||||
*/
|
||||
@DELETE
|
||||
@ExceptionParser(ReturnFalseOn404.class)
|
||||
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||
@Path("/servers/{id}")
|
||||
ListenableFuture<Boolean> deleteServer(@PathParam("id") int id);
|
||||
|
||||
|
@ -126,8 +130,7 @@ public interface CloudServersAsyncClient {
|
|||
@POST
|
||||
@QueryParams(keys = "format", values = "json")
|
||||
@Path("/servers/{id}/action")
|
||||
@ExceptionParser(ReturnFalseOn404.class)
|
||||
ListenableFuture<Boolean> rebootServer(@PathParam("id") int id,
|
||||
ListenableFuture<Void> rebootServer(@PathParam("id") int id,
|
||||
@BinderParam(BindRebootTypeToJsonPayload.class) RebootType rebootType);
|
||||
|
||||
/**
|
||||
|
@ -136,8 +139,7 @@ public interface CloudServersAsyncClient {
|
|||
@POST
|
||||
@QueryParams(keys = "format", values = "json")
|
||||
@Path("/servers/{id}/action")
|
||||
@ExceptionParser(ReturnFalseOn404.class)
|
||||
ListenableFuture<Boolean> resizeServer(@PathParam("id") int id,
|
||||
ListenableFuture<Void> resizeServer(@PathParam("id") int id,
|
||||
@BinderParam(BindResizeFlavorToJsonPayload.class) int flavorId);
|
||||
|
||||
/**
|
||||
|
@ -146,8 +148,7 @@ public interface CloudServersAsyncClient {
|
|||
@POST
|
||||
@QueryParams(keys = "format", values = "json")
|
||||
@Path("/servers/{id}/action")
|
||||
@ExceptionParser(ReturnFalseOn404.class)
|
||||
ListenableFuture<Boolean> confirmResizeServer(
|
||||
ListenableFuture<Void> confirmResizeServer(
|
||||
@PathParam("id") @BinderParam(BindConfirmResizeToJsonPayload.class) int id);
|
||||
|
||||
/**
|
||||
|
@ -156,8 +157,7 @@ public interface CloudServersAsyncClient {
|
|||
@POST
|
||||
@QueryParams(keys = "format", values = "json")
|
||||
@Path("/servers/{id}/action")
|
||||
@ExceptionParser(ReturnFalseOn404.class)
|
||||
ListenableFuture<Boolean> revertResizeServer(
|
||||
ListenableFuture<Void> revertResizeServer(
|
||||
@PathParam("id") @BinderParam(BindRevertResizeToJsonPayload.class) int id);
|
||||
|
||||
/**
|
||||
|
@ -178,18 +178,16 @@ public interface CloudServersAsyncClient {
|
|||
@POST
|
||||
@QueryParams(keys = "format", values = "json")
|
||||
@Path("/servers/{id}/action")
|
||||
@ExceptionParser(ReturnFalseOn404.class)
|
||||
@MapBinder(RebuildServerOptions.class)
|
||||
ListenableFuture<Boolean> rebuildServer(@PathParam("id") int id, RebuildServerOptions... options);
|
||||
ListenableFuture<Void> rebuildServer(@PathParam("id") int id, RebuildServerOptions... options);
|
||||
|
||||
/**
|
||||
* @see CloudServersClient#shareIp
|
||||
*/
|
||||
@PUT
|
||||
@ExceptionParser(ReturnFalseOn404.class)
|
||||
@Path("/servers/{id}/ips/public/{address}")
|
||||
@MapBinder(BindSharedIpGroupToJsonPayload.class)
|
||||
ListenableFuture<Boolean> shareIp(
|
||||
ListenableFuture<Void> shareIp(
|
||||
@PathParam("address") @ParamParser(IpAddress.class) InetAddress addressToShare,
|
||||
@PathParam("id") int serverToTosignBindressTo,
|
||||
@MapPayloadParam("sharedIpGroupId") int sharedIpGroup,
|
||||
|
@ -199,9 +197,9 @@ public interface CloudServersAsyncClient {
|
|||
* @see CloudServersClient#unshareIp
|
||||
*/
|
||||
@DELETE
|
||||
@ExceptionParser(ReturnFalseOn404.class)
|
||||
@Path("/servers/{id}/ips/public/{address}")
|
||||
ListenableFuture<Boolean> unshareIp(
|
||||
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
|
||||
ListenableFuture<Void> unshareIp(
|
||||
@PathParam("address") @ParamParser(IpAddress.class) InetAddress addressToShare,
|
||||
@PathParam("id") int serverToTosignBindressTo);
|
||||
|
||||
|
@ -209,18 +207,16 @@ public interface CloudServersAsyncClient {
|
|||
* @see CloudServersClient#changeAdminPass
|
||||
*/
|
||||
@PUT
|
||||
@ExceptionParser(ReturnFalseOn404.class)
|
||||
@Path("/servers/{id}")
|
||||
ListenableFuture<Boolean> changeAdminPass(@PathParam("id") int id,
|
||||
ListenableFuture<Void> changeAdminPass(@PathParam("id") int id,
|
||||
@BinderParam(BindAdminPassToJsonPayload.class) String adminPass);
|
||||
|
||||
/**
|
||||
* @see CloudServersClient#renameServer
|
||||
*/
|
||||
@PUT
|
||||
@ExceptionParser(ReturnFalseOn404.class)
|
||||
@Path("/servers/{id}")
|
||||
ListenableFuture<Boolean> renameServer(@PathParam("id") int id,
|
||||
ListenableFuture<Void> renameServer(@PathParam("id") int id,
|
||||
@BinderParam(BindServerNameToJsonPayload.class) String newName);
|
||||
|
||||
/**
|
||||
|
@ -239,6 +235,7 @@ public interface CloudServersAsyncClient {
|
|||
@ResponseParser(ParseFlavorFromJsonResponse.class)
|
||||
@QueryParams(keys = "format", values = "json")
|
||||
@Path("/flavors/{id}")
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
ListenableFuture<Flavor> getFlavor(@PathParam("id") int id);
|
||||
|
||||
/**
|
||||
|
@ -255,6 +252,7 @@ public interface CloudServersAsyncClient {
|
|||
*/
|
||||
@GET
|
||||
@ResponseParser(ParseImageFromJsonResponse.class)
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
@QueryParams(keys = "format", values = "json")
|
||||
@Path("/images/{id}")
|
||||
ListenableFuture<Image> getImage(@PathParam("id") int id);
|
||||
|
@ -263,7 +261,7 @@ public interface CloudServersAsyncClient {
|
|||
* @see CloudServersClient#deleteImage
|
||||
*/
|
||||
@DELETE
|
||||
@ExceptionParser(ReturnFalseOn404.class)
|
||||
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||
@Path("/images/{id}")
|
||||
ListenableFuture<Boolean> deleteImage(@PathParam("id") int id);
|
||||
|
||||
|
@ -294,6 +292,7 @@ public interface CloudServersAsyncClient {
|
|||
@ResponseParser(ParseSharedIpGroupFromJsonResponse.class)
|
||||
@QueryParams(keys = "format", values = "json")
|
||||
@Path("/shared_ip_groups/{id}")
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
ListenableFuture<SharedIpGroup> getSharedIpGroup(@PathParam("id") int id);
|
||||
|
||||
/**
|
||||
|
@ -311,7 +310,7 @@ public interface CloudServersAsyncClient {
|
|||
* @see CloudServersClient#deleteSharedIpGroup
|
||||
*/
|
||||
@DELETE
|
||||
@ExceptionParser(ReturnFalseOn404.class)
|
||||
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||
@Path("/shared_ip_groups/{id}")
|
||||
ListenableFuture<Boolean> deleteSharedIpGroup(@PathParam("id") int id);
|
||||
|
||||
|
@ -322,13 +321,13 @@ public interface CloudServersAsyncClient {
|
|||
@ResponseParser(ParseBackupScheduleFromJsonResponse.class)
|
||||
@QueryParams(keys = "format", values = "json")
|
||||
@Path("/servers/{id}/backup_schedule")
|
||||
ListenableFuture<BackupSchedule> listBackupSchedule(@PathParam("id") int serverId);
|
||||
ListenableFuture<BackupSchedule> getBackupSchedule(@PathParam("id") int serverId);
|
||||
|
||||
/**
|
||||
* @see CloudServersClient#deleteBackupSchedule
|
||||
*/
|
||||
@DELETE
|
||||
@ExceptionParser(ReturnFalseOn404.class)
|
||||
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||
@Path("/servers/{id}/backup_schedule")
|
||||
ListenableFuture<Boolean> deleteBackupSchedule(@PathParam("id") int serverId);
|
||||
|
||||
|
@ -338,7 +337,7 @@ public interface CloudServersAsyncClient {
|
|||
@POST
|
||||
@ExceptionParser(ReturnFalseOn404.class)
|
||||
@Path("/servers/{id}/backup_schedule")
|
||||
ListenableFuture<Boolean> replaceBackupSchedule(@PathParam("id") int id,
|
||||
ListenableFuture<Void> replaceBackupSchedule(@PathParam("id") int id,
|
||||
@BinderParam(BindBackupScheduleToJsonPayload.class) BackupSchedule backupSchedule);
|
||||
|
||||
/**
|
||||
|
@ -348,7 +347,7 @@ public interface CloudServersAsyncClient {
|
|||
@ResponseParser(ParseAddressesFromJsonResponse.class)
|
||||
@QueryParams(keys = "format", values = "json")
|
||||
@Path("/servers/{id}/ips")
|
||||
ListenableFuture<Addresses> listAddresses(@PathParam("id") int serverId);
|
||||
ListenableFuture<Addresses> getAddresses(@PathParam("id") int serverId);
|
||||
|
||||
/**
|
||||
* @see CloudServersClient#listPublicAddresses
|
||||
|
|
|
@ -71,8 +71,7 @@ public interface CloudServersClient {
|
|||
*
|
||||
* This operation returns details of the specified server.
|
||||
*
|
||||
* @throws ResourceNotFoundException
|
||||
* if the server is not found
|
||||
* @return null, if the server is not found
|
||||
* @see Server
|
||||
*/
|
||||
Server getServer(@PathParam("id") int id);
|
||||
|
@ -102,7 +101,7 @@ public interface CloudServersClient {
|
|||
* graceful shutdown of all processes. A hard reboot is the equivalent of power cycling
|
||||
* the server.
|
||||
*/
|
||||
boolean rebootServer(int id, RebootType rebootType);
|
||||
void rebootServer(int id, RebootType rebootType);
|
||||
|
||||
/**
|
||||
* The resize function converts an existing server to a different flavor, in essence, scaling the
|
||||
|
@ -117,7 +116,7 @@ public interface CloudServersClient {
|
|||
* <p/>
|
||||
* ACTIVE - QUEUE_RESIZE - ACTIVE (on error)
|
||||
*/
|
||||
boolean resizeServer(int id, int flavorId);
|
||||
void resizeServer(int id, int flavorId);
|
||||
|
||||
/**
|
||||
* The resize function converts an existing server to a different flavor, in essence, scaling the
|
||||
|
@ -130,7 +129,7 @@ public interface CloudServersClient {
|
|||
* <p/>
|
||||
* VERIFY_RESIZE - ACTIVE
|
||||
*/
|
||||
boolean confirmResizeServer(int id);
|
||||
void confirmResizeServer(int id);
|
||||
|
||||
/**
|
||||
* The resize function converts an existing server to a different flavor, in essence, scaling the
|
||||
|
@ -143,7 +142,7 @@ public interface CloudServersClient {
|
|||
* <p/>
|
||||
* VERIFY_RESIZE - ACTIVE
|
||||
*/
|
||||
boolean revertResizeServer(int id);
|
||||
void revertResizeServer(int id);
|
||||
|
||||
/**
|
||||
* This operation asynchronously provisions a new server. The progress of this operation depends
|
||||
|
@ -173,7 +172,7 @@ public interface CloudServersClient {
|
|||
* - imageId is an optional argument. If it is not specified, the server is rebuilt
|
||||
* with the original imageId.
|
||||
*/
|
||||
boolean rebuildServer(int id, RebuildServerOptions... options);
|
||||
void rebuildServer(int id, RebuildServerOptions... options);
|
||||
|
||||
/**
|
||||
* /** This operation allows you share an IP address to the specified server
|
||||
|
@ -194,9 +193,8 @@ public interface CloudServersClient {
|
|||
* If set to false, does not bind the IP to the server itself. A heartbeat facility
|
||||
* (e.g. keepalived) can then be used within the servers to perform health checks and
|
||||
* manage IP failover.
|
||||
* @return false if the server is not found
|
||||
*/
|
||||
boolean shareIp(InetAddress addressToShare, int serverToTosignBindressTo, int sharedIpGroup,
|
||||
void shareIp(InetAddress addressToShare, int serverToTosignBindressTo, int sharedIpGroup,
|
||||
boolean configureServer);
|
||||
|
||||
/**
|
||||
|
@ -208,16 +206,15 @@ public interface CloudServersClient {
|
|||
* @param serverToTosignBindressTo
|
||||
* @return
|
||||
*/
|
||||
boolean unshareIp(InetAddress addressToShare, int serverToTosignBindressTo);
|
||||
void unshareIp(InetAddress addressToShare, int serverToTosignBindressTo);
|
||||
|
||||
/**
|
||||
* This operation allows you to change the administrative password.
|
||||
* <p/>
|
||||
* Status Transition: ACTIVE - PASSWORD - ACTIVE
|
||||
*
|
||||
* @return false if the server is not found
|
||||
*/
|
||||
boolean changeAdminPass(int id, String adminPass);
|
||||
void changeAdminPass(int id, String adminPass);
|
||||
|
||||
/**
|
||||
* This operation allows you to update the name of the server. This operation changes the name of
|
||||
|
@ -225,9 +222,8 @@ public interface CloudServersClient {
|
|||
* <p/>
|
||||
* Status Transition: ACTIVE - PASSWORD - ACTIVE
|
||||
*
|
||||
* @return false if the server is not found
|
||||
*/
|
||||
boolean renameServer(int id, String newName);
|
||||
void renameServer(int id, String newName);
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -242,8 +238,7 @@ public interface CloudServersClient {
|
|||
*
|
||||
* This operation returns details of the specified flavor.
|
||||
*
|
||||
* @throws ResourceNotFoundException
|
||||
* if the flavor is not found
|
||||
* @return null, if the flavor is not found
|
||||
* @see Flavor
|
||||
*/
|
||||
Flavor getFlavor(int id);
|
||||
|
@ -261,8 +256,8 @@ public interface CloudServersClient {
|
|||
*
|
||||
* This operation returns details of the specified image.
|
||||
*
|
||||
* @throws ResourceNotFoundException
|
||||
* if the image is not found
|
||||
* @return null, if the image is not found
|
||||
*
|
||||
* @see Image
|
||||
*/
|
||||
Image getImage(int id);
|
||||
|
@ -314,8 +309,8 @@ public interface CloudServersClient {
|
|||
*
|
||||
* This operation returns details of the specified shared IP group.
|
||||
*
|
||||
* @throws ResourceNotFoundException
|
||||
* if the shared IP group is not found
|
||||
* @return null, if the shared ip group is not found
|
||||
*
|
||||
* @see SharedIpGroup
|
||||
*/
|
||||
SharedIpGroup getSharedIpGroup(int id);
|
||||
|
@ -340,37 +335,48 @@ public interface CloudServersClient {
|
|||
|
||||
/**
|
||||
* List the backup schedule for the specified server
|
||||
*
|
||||
* @throws ResourceNotFoundException
|
||||
* , if the server doesn't exist
|
||||
*/
|
||||
BackupSchedule listBackupSchedule(int serverId);
|
||||
BackupSchedule getBackupSchedule(int serverId);
|
||||
|
||||
/**
|
||||
* Delete backup schedule for the specified server.
|
||||
* <p/>
|
||||
* Web Hosting #119571 currently disables the schedule, not deletes it.
|
||||
*
|
||||
* @return false if the server is not found
|
||||
* @return false if the schedule is not found
|
||||
*/
|
||||
boolean deleteBackupSchedule(int serverId);
|
||||
|
||||
/**
|
||||
* Enable/update the backup schedule for the specified server
|
||||
*
|
||||
* @return false if the server is not found
|
||||
*/
|
||||
boolean replaceBackupSchedule(int id, BackupSchedule backupSchedule);
|
||||
void replaceBackupSchedule(int id, BackupSchedule backupSchedule);
|
||||
|
||||
/**
|
||||
* List all server addresses
|
||||
*
|
||||
* @throws ResourceNotFoundException
|
||||
* , if the server doesn't exist
|
||||
*/
|
||||
Addresses listAddresses(int serverId);
|
||||
Addresses getAddresses(int serverId);
|
||||
|
||||
/**
|
||||
* List all public server addresses
|
||||
*
|
||||
* @throws ResourceNotFoundException
|
||||
* , if the server doesn't exist
|
||||
*/
|
||||
List<InetAddress> listPublicAddresses(int serverId);
|
||||
|
||||
/**
|
||||
* List all private server addresses
|
||||
*
|
||||
* @throws ResourceNotFoundException
|
||||
* , if the server doesn't exist
|
||||
*/
|
||||
List<InetAddress> listPrivateAddresses(int serverId);
|
||||
|
||||
|
|
|
@ -20,44 +20,31 @@ 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;
|
||||
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.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.NodeMetadataImpl;
|
||||
import org.jclouds.compute.domain.internal.NodeSetImpl;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.compute.internal.BaseComputeService;
|
||||
import org.jclouds.compute.util.ComputeUtils;
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.rackspace.cloudservers.CloudServersClient;
|
||||
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;
|
||||
|
||||
|
@ -65,144 +52,44 @@ 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 {
|
||||
public class CloudServersComputeService extends BaseComputeService {
|
||||
|
||||
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<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 String nodeNamingConvention;
|
||||
private final ComputeUtils utils;
|
||||
private final CloudServersClient client;
|
||||
private final Predicate<Server> serverActive;
|
||||
private final ServerToNodeMetadata serverToNodeMetadata;
|
||||
private final Predicate<Server> serverDeleted;
|
||||
protected final ExecutorService executor;
|
||||
private final Function<Server, NodeMetadata> serverToNodeMetadata;
|
||||
|
||||
@Inject
|
||||
public CloudServersComputeService(CloudServersClient client,
|
||||
Provider<TemplateBuilder> templateBuilderProvider,
|
||||
public CloudServersComputeService(Provider<TemplateBuilder> templateBuilderProvider,
|
||||
Provider<Map<String, ? extends Image>> images,
|
||||
Provider<Map<String, ? extends Size>> sizes,
|
||||
Provider<Map<String, ? extends Location>> locations, ComputeUtils utils,
|
||||
CloudServersClient client, Function<Server, NodeMetadata> serverToNodeMetadata,
|
||||
@Named("ACTIVE") Predicate<Server> serverActive,
|
||||
@Named("DELETED") Predicate<Server> serverDeleted,
|
||||
@Named(RackspaceConstants.PROPERTY_RACKSPACE_USER) String account,
|
||||
ServerToNodeMetadata serverToNodeMetadata,
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
|
||||
super(images, sizes, locations, templateBuilderProvider, account + "-%s-%d", utils, 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.serverToNodeMetadata = serverToNodeMetadata;
|
||||
this.executor = executor;
|
||||
this.nodeNamingConvention = account + "-%s-%d";
|
||||
}
|
||||
|
||||
private static Map<ServerStatus, NodeState> serverToNodeState = ImmutableMap
|
||||
.<ServerStatus, NodeState> builder().put(ServerStatus.ACTIVE, NodeState.RUNNING)//
|
||||
.put(ServerStatus.SUSPENDED, NodeState.SUSPENDED)//
|
||||
.put(ServerStatus.DELETED, NodeState.TERMINATED)//
|
||||
.put(ServerStatus.QUEUE_RESIZE, NodeState.PENDING)//
|
||||
.put(ServerStatus.PREP_RESIZE, NodeState.PENDING)//
|
||||
.put(ServerStatus.RESIZE, NodeState.PENDING)//
|
||||
.put(ServerStatus.VERIFY_RESIZE, NodeState.PENDING)//
|
||||
.put(ServerStatus.QUEUE_MOVE, NodeState.PENDING)//
|
||||
.put(ServerStatus.PREP_MOVE, NodeState.PENDING)//
|
||||
.put(ServerStatus.MOVE, NodeState.PENDING)//
|
||||
.put(ServerStatus.VERIFY_MOVE, NodeState.PENDING)//
|
||||
.put(ServerStatus.RESCUE, NodeState.PENDING)//
|
||||
.put(ServerStatus.ERROR, NodeState.ERROR)//
|
||||
.put(ServerStatus.BUILD, NodeState.PENDING)//
|
||||
.put(ServerStatus.RESTORING, NodeState.PENDING)//
|
||||
.put(ServerStatus.PASSWORD, NodeState.PENDING)//
|
||||
.put(ServerStatus.REBUILD, NodeState.PENDING)//
|
||||
.put(ServerStatus.DELETE_IP, NodeState.PENDING)//
|
||||
.put(ServerStatus.SHARE_IP_NO_CONFIG, NodeState.PENDING)//
|
||||
.put(ServerStatus.SHARE_IP, NodeState.PENDING)//
|
||||
.put(ServerStatus.REBOOT, NodeState.PENDING)//
|
||||
.put(ServerStatus.HARD_REBOOT, NodeState.PENDING)//
|
||||
.put(ServerStatus.UNKNOWN, NodeState.UNKNOWN).build();
|
||||
|
||||
@Override
|
||||
public NodeSet runNodesWithTag(final String tag, int count, final Template template) {
|
||||
checkArgument(tag.indexOf('-') == -1, "tag cannot contain hyphens");
|
||||
checkNotNull(template.getLocation(), "location");
|
||||
final Set<NodeMetadata> nodes = Sets.newHashSet();
|
||||
int nodesToStart = count;
|
||||
int i = 0;
|
||||
while (nodesToStart > 0) {
|
||||
int currentCount = i;
|
||||
Map<String, ListenableFuture<Void>> responses = Maps.newHashMap();
|
||||
for (; i < currentCount + nodesToStart; i++) {
|
||||
final String name = String.format(nodeNamingConvention, tag, i + 1);
|
||||
responses.put(name, makeListenable(executor.submit(new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
NodeMetadata node = null;
|
||||
try {
|
||||
node = startServerAndConvertToNode(tag, name, template);
|
||||
logger.debug("<< running server(%s)", node.getId());
|
||||
utils.runOptionsOnNode(node, template.getOptions());
|
||||
logger.debug("<< options applied server(%s)", node.getId());
|
||||
nodes.add(node);
|
||||
} catch (Exception e) {
|
||||
if (node != null) {
|
||||
destroyNode(node);
|
||||
logger.error(e, "<< error applying server(%s) [%s] destroying ", name, e
|
||||
.getMessage());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}), executor));
|
||||
}
|
||||
nodesToStart = awaitCompletion(responses, executor, null, logger, "nodes").size();
|
||||
}
|
||||
return new NodeSetImpl(nodes);
|
||||
}
|
||||
|
||||
private NodeMetadata startServerAndConvertToNode(final String tag, final String name,
|
||||
final Template template) {
|
||||
protected NodeMetadata startNode(final String tag, final String name, final Template template) {
|
||||
Server server = client.createServer(name, Integer.parseInt(template.getImage().getId()),
|
||||
Integer.parseInt(template.getSize().getId()));
|
||||
logger.debug("<< started server(%s)", server.getId());
|
||||
serverActive.apply(server);
|
||||
return new NodeMetadataImpl(server.getId() + "", name, null, null, server.getMetadata(), tag,
|
||||
return new NodeMetadataImpl(server.getId() + "", name, template.getLocation().getId(), null, server.getMetadata(), tag,
|
||||
NodeState.RUNNING, server.getAddresses().getPublicAddresses(), server.getAddresses()
|
||||
.getPrivateAddresses(), ImmutableMap.<String, String> of(),
|
||||
new Credentials("root", server.getAdminPass()));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -210,131 +97,25 @@ public class CloudServersComputeService implements ComputeService {
|
|||
checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not "
|
||||
+ node.getType());
|
||||
checkNotNull(node.getId(), "node.id");
|
||||
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 Location location;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Inject
|
||||
ServerToNodeMetadata(Location location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeMetadata apply(Server from) {
|
||||
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 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
|
||||
.listServers(ListOptions.Builder.withDetails()), serverToNodeMetadata),
|
||||
METADATA_TO_ID);
|
||||
return map;
|
||||
}
|
||||
|
||||
@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");
|
||||
|
||||
logger.debug(">> deleting server(%s)", node.getId());
|
||||
int serverId = Integer.parseInt(node.getId());
|
||||
client.deleteServer(serverId);
|
||||
boolean successful = serverDeleted.apply(client.getServer(serverId));
|
||||
logger.debug("<< deleted server(%s) success(%s)", node.getId(), successful);
|
||||
Server server = client.getServer(serverId);
|
||||
return server == null ? null : serverToNodeMetadata.apply(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyNodesWithTag(String tag) { // TODO parallel
|
||||
logger.debug(">> terminating servers by tag(%s)", tag);
|
||||
Iterable<NodeMetadata> nodesToDestroy = Iterables.filter(doGetNodes(tag),
|
||||
new Predicate<NodeMetadata>() {
|
||||
@Override
|
||||
public boolean apply(NodeMetadata input) {
|
||||
return input.getState() != NodeState.TERMINATED;
|
||||
|
||||
}
|
||||
});
|
||||
Map<NodeMetadata, ListenableFuture<Void>> responses = Maps.newHashMap();
|
||||
for (final NodeMetadata node : nodesToDestroy) {
|
||||
responses.put(node, 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");
|
||||
protected Iterable<NodeMetadata> doGetNodes() {
|
||||
return Iterables.transform(client.listServers(ListOptions.Builder.withDetails()),
|
||||
serverToNodeMetadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends Location> getLocations() {
|
||||
return locations.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeSet getNodesWithTag(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 Map<String, ? extends Image> getImages() {
|
||||
return images.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemplateBuilder templateBuilder() {
|
||||
return templateBuilderProvider.get();
|
||||
protected boolean doDestroyNode(ComputeMetadata node) {
|
||||
int serverId = Integer.parseInt(node.getId());
|
||||
// if false server wasn't around in the first place
|
||||
if (!client.deleteServer(serverId))
|
||||
return false;
|
||||
Server server = client.getServer(serverId);
|
||||
return server == null ? false : serverDeleted.apply(server);
|
||||
}
|
||||
|
||||
}
|
|
@ -28,6 +28,7 @@ import java.util.regex.Matcher;
|
|||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
|
@ -37,9 +38,12 @@ 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.NodeMetadata;
|
||||
import org.jclouds.compute.domain.NodeState;
|
||||
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.NodeMetadataImpl;
|
||||
import org.jclouds.compute.domain.internal.SizeImpl;
|
||||
import org.jclouds.compute.internal.ComputeServiceContextImpl;
|
||||
import org.jclouds.compute.predicates.RunScriptRunning;
|
||||
|
@ -54,6 +58,8 @@ import org.jclouds.rackspace.cloudservers.CloudServersClient;
|
|||
import org.jclouds.rackspace.cloudservers.compute.CloudServersComputeService;
|
||||
import org.jclouds.rackspace.cloudservers.config.CloudServersContextModule;
|
||||
import org.jclouds.rackspace.cloudservers.domain.Flavor;
|
||||
import org.jclouds.rackspace.cloudservers.domain.Server;
|
||||
import org.jclouds.rackspace.cloudservers.domain.ServerStatus;
|
||||
import org.jclouds.rackspace.cloudservers.options.ListOptions;
|
||||
import org.jclouds.rest.RestContext;
|
||||
import org.jclouds.ssh.SshClient;
|
||||
|
@ -66,6 +72,7 @@ import com.google.common.collect.ImmutableSet;
|
|||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
/**
|
||||
* Configures the {@link CloudServersComputeServiceContext}; requires
|
||||
|
@ -79,6 +86,59 @@ public class CloudServersComputeServiceContextModule extends CloudServersContext
|
|||
protected void configure() {
|
||||
super.configure();
|
||||
bind(ComputeService.class).to(CloudServersComputeService.class).asEagerSingleton();
|
||||
bind(new TypeLiteral<Function<Server, NodeMetadata>>() {
|
||||
}).to(ServerToNodeMetadata.class);
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
Map<ServerStatus, NodeState> provideServerToNodeState() {
|
||||
return ImmutableMap.<ServerStatus, NodeState> builder().put(ServerStatus.ACTIVE,
|
||||
NodeState.RUNNING)//
|
||||
.put(ServerStatus.SUSPENDED, NodeState.SUSPENDED)//
|
||||
.put(ServerStatus.DELETED, NodeState.TERMINATED)//
|
||||
.put(ServerStatus.QUEUE_RESIZE, NodeState.PENDING)//
|
||||
.put(ServerStatus.PREP_RESIZE, NodeState.PENDING)//
|
||||
.put(ServerStatus.RESIZE, NodeState.PENDING)//
|
||||
.put(ServerStatus.VERIFY_RESIZE, NodeState.PENDING)//
|
||||
.put(ServerStatus.QUEUE_MOVE, NodeState.PENDING)//
|
||||
.put(ServerStatus.PREP_MOVE, NodeState.PENDING)//
|
||||
.put(ServerStatus.MOVE, NodeState.PENDING)//
|
||||
.put(ServerStatus.VERIFY_MOVE, NodeState.PENDING)//
|
||||
.put(ServerStatus.RESCUE, NodeState.PENDING)//
|
||||
.put(ServerStatus.ERROR, NodeState.ERROR)//
|
||||
.put(ServerStatus.BUILD, NodeState.PENDING)//
|
||||
.put(ServerStatus.RESTORING, NodeState.PENDING)//
|
||||
.put(ServerStatus.PASSWORD, NodeState.PENDING)//
|
||||
.put(ServerStatus.REBUILD, NodeState.PENDING)//
|
||||
.put(ServerStatus.DELETE_IP, NodeState.PENDING)//
|
||||
.put(ServerStatus.SHARE_IP_NO_CONFIG, NodeState.PENDING)//
|
||||
.put(ServerStatus.SHARE_IP, NodeState.PENDING)//
|
||||
.put(ServerStatus.REBOOT, NodeState.PENDING)//
|
||||
.put(ServerStatus.HARD_REBOOT, NodeState.PENDING)//
|
||||
.put(ServerStatus.UNKNOWN, NodeState.UNKNOWN).build();
|
||||
}
|
||||
|
||||
protected static class ServerToNodeMetadata implements Function<Server, NodeMetadata> {
|
||||
public static final Pattern TAG_PATTERN = Pattern.compile("[^-]+-([^-]+)-[0-9]+");
|
||||
private final Location location;
|
||||
private final Map<ServerStatus, NodeState> serverToNodeState;
|
||||
|
||||
@Inject
|
||||
ServerToNodeMetadata(Location location, Map<ServerStatus, NodeState> serverToNodeState) {
|
||||
this.location = location;
|
||||
this.serverToNodeState = serverToNodeState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeMetadata apply(Server from) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.jclouds.rackspace.cloudservers.predicates;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
|
@ -7,7 +9,6 @@ import org.jclouds.logging.Logger;
|
|||
import org.jclouds.rackspace.cloudservers.CloudServersClient;
|
||||
import org.jclouds.rackspace.cloudservers.domain.Server;
|
||||
import org.jclouds.rackspace.cloudservers.domain.ServerStatus;
|
||||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.inject.Inject;
|
||||
|
@ -32,15 +33,13 @@ public class ServerActive implements Predicate<Server> {
|
|||
}
|
||||
|
||||
public boolean apply(Server server) {
|
||||
logger.trace("looking for state on server %s", server);
|
||||
try {
|
||||
server = refresh(server);
|
||||
logger.trace("%s: looking for server state %s: currently: %s", server.getId(),
|
||||
ServerStatus.ACTIVE, server.getStatus());
|
||||
return server.getStatus() == ServerStatus.ACTIVE;
|
||||
} catch (ResourceNotFoundException e) {
|
||||
logger.trace("looking for state on server %s", checkNotNull(server, "server"));
|
||||
server = refresh(server);
|
||||
if (server == null)
|
||||
return false;
|
||||
}
|
||||
logger.trace("%s: looking for server state %s: currently: %s", server.getId(),
|
||||
ServerStatus.ACTIVE, server.getStatus());
|
||||
return server.getStatus() == ServerStatus.ACTIVE;
|
||||
}
|
||||
|
||||
private Server refresh(Server server) {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.jclouds.rackspace.cloudservers.predicates;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
|
@ -7,7 +9,6 @@ import org.jclouds.logging.Logger;
|
|||
import org.jclouds.rackspace.cloudservers.CloudServersClient;
|
||||
import org.jclouds.rackspace.cloudservers.domain.Server;
|
||||
import org.jclouds.rackspace.cloudservers.domain.ServerStatus;
|
||||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.inject.Inject;
|
||||
|
@ -32,15 +33,13 @@ public class ServerDeleted implements Predicate<Server> {
|
|||
}
|
||||
|
||||
public boolean apply(Server server) {
|
||||
logger.trace("looking for state on server %s", server);
|
||||
try {
|
||||
server = refresh(server);
|
||||
logger.trace("%s: looking for server state %s: currently: %s", server.getId(),
|
||||
ServerStatus.DELETED, server.getStatus());
|
||||
return server.getStatus() == ServerStatus.DELETED;
|
||||
} catch (ResourceNotFoundException e) {
|
||||
logger.trace("looking for state on server %s", checkNotNull(server, "server"));
|
||||
server = refresh(server);
|
||||
if (server == null)
|
||||
return true;
|
||||
}
|
||||
logger.trace("%s: looking for server state %s: currently: %s", server.getId(),
|
||||
ServerStatus.DELETED, server.getStatus());
|
||||
return server.getStatus() == ServerStatus.DELETED;
|
||||
}
|
||||
|
||||
private Server refresh(Server server) {
|
||||
|
|
|
@ -52,7 +52,6 @@ import org.jclouds.rackspace.cloudservers.domain.ServerStatus;
|
|||
import org.jclouds.rackspace.cloudservers.domain.SharedIpGroup;
|
||||
import org.jclouds.rackspace.cloudservers.domain.WeeklyBackup;
|
||||
import org.jclouds.rackspace.cloudservers.options.RebuildServerOptions;
|
||||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
import org.jclouds.ssh.ExecResponse;
|
||||
import org.jclouds.ssh.SshClient;
|
||||
import org.jclouds.ssh.SshException;
|
||||
|
@ -148,19 +147,14 @@ public class CloudServersClientLiveTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = ResourceNotFoundException.class)
|
||||
@Test
|
||||
public void testGetImageDetailsNotFound() throws Exception {
|
||||
try {
|
||||
client.getImage(12312987);
|
||||
} catch (HttpResponseException e) {// Ticket #9867
|
||||
if (e.getResponse().getStatusCode() != 400)
|
||||
throw e;
|
||||
}
|
||||
assert client.getImage(12312987) == null;
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = ResourceNotFoundException.class)
|
||||
@Test
|
||||
public void testGetServerDetailsNotFound() throws Exception {
|
||||
client.getServer(12312987);
|
||||
assert client.getServer(12312987) == null;
|
||||
}
|
||||
|
||||
public void testGetServersDetail() throws Exception {
|
||||
|
@ -210,9 +204,9 @@ public class CloudServersClientLiveTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = ResourceNotFoundException.class)
|
||||
@Test
|
||||
public void testGetFlavorDetailsNotFound() throws Exception {
|
||||
client.getFlavor(12312987);
|
||||
assert client.getFlavor(12312987) == null;
|
||||
}
|
||||
|
||||
public void testListSharedIpGroups() throws Exception {
|
||||
|
@ -250,9 +244,9 @@ public class CloudServersClientLiveTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = ResourceNotFoundException.class)
|
||||
@Test
|
||||
public void testGetSharedIpGroupDetailsNotFound() throws Exception {
|
||||
client.getSharedIpGroup(12312987);
|
||||
assert client.getSharedIpGroup(12312987) == null;
|
||||
}
|
||||
|
||||
@Test(timeOut = 5 * 60 * 1000, dependsOnMethods = "testCreateServer")
|
||||
|
@ -349,7 +343,7 @@ public class CloudServersClientLiveTest {
|
|||
assertEquals(new Integer(1), server.getFlavorId());
|
||||
assertNotNull(server.getAddresses());
|
||||
// listAddresses tests..
|
||||
assertEquals(client.listAddresses(serverId), server.getAddresses());
|
||||
assertEquals(client.getAddresses(serverId), server.getAddresses());
|
||||
assertEquals(server.getAddresses().getPublicAddresses().size(), 1);
|
||||
assertEquals(client.listPublicAddresses(serverId), server.getAddresses().getPublicAddresses());
|
||||
assertEquals(server.getAddresses().getPrivateAddresses().size(), 1);
|
||||
|
@ -412,14 +406,14 @@ public class CloudServersClientLiveTest {
|
|||
public void testRenameServer() throws Exception {
|
||||
Server server = client.getServer(serverId);
|
||||
String oldName = server.getName();
|
||||
assertTrue(client.renameServer(serverId, oldName + "new"));
|
||||
client.renameServer(serverId, oldName + "new");
|
||||
blockUntilServerActive(serverId);
|
||||
assertEquals(oldName + "new", client.getServer(serverId).getName());
|
||||
}
|
||||
|
||||
@Test(timeOut = 5 * 60 * 1000, dependsOnMethods = "testCreateServer")
|
||||
public void testChangePassword() throws Exception {
|
||||
assertTrue(client.changeAdminPass(serverId, "elmo"));
|
||||
client.changeAdminPass(serverId, "elmo");
|
||||
blockUntilServerActive(serverId);
|
||||
checkPassOk(client.getServer(serverId), "elmo");
|
||||
this.adminPass = "elmo";
|
||||
|
@ -508,15 +502,15 @@ public class CloudServersClientLiveTest {
|
|||
|
||||
@Test(timeOut = 10 * 60 * 1000, dependsOnMethods = "testShareNoConfig")
|
||||
public void testBackup() throws Exception {
|
||||
assertEquals(new BackupSchedule(), client.listBackupSchedule(serverId));
|
||||
assertEquals(new BackupSchedule(), client.getBackupSchedule(serverId));
|
||||
BackupSchedule dailyWeekly = new BackupSchedule();
|
||||
dailyWeekly.setEnabled(true);
|
||||
dailyWeekly.setWeekly(WeeklyBackup.FRIDAY);
|
||||
dailyWeekly.setDaily(DailyBackup.H_0400_0600);
|
||||
assertEquals(true, client.replaceBackupSchedule(serverId, dailyWeekly));
|
||||
client.replaceBackupSchedule(serverId, dailyWeekly);
|
||||
client.deleteBackupSchedule(serverId);
|
||||
// disables, doesn't delete: Web Hosting #119571
|
||||
assertEquals(client.listBackupSchedule(serverId).isEnabled(), false);
|
||||
assertEquals(client.getBackupSchedule(serverId).isEnabled(), false);
|
||||
}
|
||||
|
||||
@Test(timeOut = 10 * 60 * 1000, dependsOnMethods = "testBackup")
|
||||
|
@ -530,7 +524,7 @@ public class CloudServersClientLiveTest {
|
|||
|
||||
@Test(timeOut = 10 * 60 * 1000, dependsOnMethods = "testCreateImage")
|
||||
public void testRebuildServer() throws Exception {
|
||||
assertTrue(client.rebuildServer(serverId, new RebuildServerOptions().withImage(imageId)));
|
||||
client.rebuildServer(serverId, new RebuildServerOptions().withImage(imageId));
|
||||
blockUntilServerActive(serverId);
|
||||
// issue Web Hosting #119580 imageId comes back incorrect after rebuild
|
||||
// assertEquals(new Integer(imageId), client.getServer(serverId).getImageId());
|
||||
|
@ -538,64 +532,64 @@ public class CloudServersClientLiveTest {
|
|||
|
||||
@Test(timeOut = 10 * 60 * 1000, dependsOnMethods = "testRebuildServer")
|
||||
public void testRebootHard() throws Exception {
|
||||
assertTrue(client.rebootServer(serverId, RebootType.HARD));
|
||||
client.rebootServer(serverId, RebootType.HARD);
|
||||
blockUntilServerActive(serverId);
|
||||
}
|
||||
|
||||
@Test(timeOut = 10 * 60 * 1000, dependsOnMethods = "testRebootHard")
|
||||
public void testRebootSoft() throws Exception {
|
||||
assertTrue(client.rebootServer(serverId, RebootType.SOFT));
|
||||
client.rebootServer(serverId, RebootType.SOFT);
|
||||
blockUntilServerActive(serverId);
|
||||
}
|
||||
|
||||
@Test(timeOut = 10 * 60 * 1000, dependsOnMethods = "testRebootSoft")
|
||||
public void testRevertResize() throws Exception {
|
||||
assertTrue(client.resizeServer(serverId, 2));
|
||||
client.resizeServer(serverId, 2);
|
||||
blockUntilServerVerifyResize(serverId);
|
||||
assertTrue(client.revertResizeServer(serverId));
|
||||
client.revertResizeServer(serverId);
|
||||
blockUntilServerActive(serverId);
|
||||
assertEquals(new Integer(1), client.getServer(serverId).getFlavorId());
|
||||
}
|
||||
|
||||
@Test(timeOut = 10 * 60 * 1000, dependsOnMethods = "testRebootSoft")
|
||||
public void testConfirmResize() throws Exception {
|
||||
assertTrue(client.resizeServer(serverId2, 2));
|
||||
client.resizeServer(serverId2, 2);
|
||||
blockUntilServerVerifyResize(serverId2);
|
||||
assertTrue(client.confirmResizeServer(serverId2));
|
||||
client.confirmResizeServer(serverId2);
|
||||
blockUntilServerActive(serverId2);
|
||||
assertEquals(new Integer(2), client.getServer(serverId2).getFlavorId());
|
||||
}
|
||||
|
||||
@Test(timeOut = 10 * 60 * 1000, dependsOnMethods = { "testRebootSoft", "testRevertResize",
|
||||
"testConfirmResize" }, expectedExceptions = ResourceNotFoundException.class)
|
||||
"testConfirmResize" })
|
||||
void deleteServer2() {
|
||||
if (serverId2 > 0) {
|
||||
client.deleteServer(serverId2);
|
||||
client.getServer(serverId2);
|
||||
assert client.getServer(serverId2) == null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeOut = 10 * 60 * 1000, dependsOnMethods = "deleteServer2", expectedExceptions = ResourceNotFoundException.class)
|
||||
@Test(timeOut = 10 * 60 * 1000, dependsOnMethods = "deleteServer2")
|
||||
void testDeleteImage() {
|
||||
if (imageId > 0) {
|
||||
client.deleteImage(imageId);
|
||||
client.getImage(imageId);
|
||||
assert client.getImage(imageId) == null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeOut = 10 * 60 * 1000, dependsOnMethods = "testDeleteImage", expectedExceptions = ResourceNotFoundException.class)
|
||||
@Test(timeOut = 10 * 60 * 1000, dependsOnMethods = "testDeleteImage")
|
||||
void deleteServer1() {
|
||||
if (serverId > 0) {
|
||||
client.deleteServer(serverId);
|
||||
client.getServer(serverId);
|
||||
assert client.getServer(serverId) == null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeOut = 10 * 60 * 1000, dependsOnMethods = { "deleteServer1" }, expectedExceptions = ResourceNotFoundException.class)
|
||||
@Test(timeOut = 10 * 60 * 1000, dependsOnMethods = { "deleteServer1" })
|
||||
void testDeleteSharedIpGroup() {
|
||||
if (sharedIpGroupId > 0) {
|
||||
client.deleteSharedIpGroup(sharedIpGroupId);
|
||||
client.getSharedIpGroup(sharedIpGroupId);
|
||||
assert client.getSharedIpGroup(sharedIpGroupId) == null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ import javax.ws.rs.core.MediaType;
|
|||
import org.jclouds.concurrent.config.ExecutorServiceModule;
|
||||
import org.jclouds.date.TimeStamp;
|
||||
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
|
||||
import org.jclouds.http.functions.CloseContentAndReturn;
|
||||
import org.jclouds.http.functions.ReturnFalseOn404;
|
||||
import org.jclouds.http.functions.ReturnTrueIf2xx;
|
||||
import org.jclouds.logging.Logger;
|
||||
|
@ -70,6 +71,9 @@ import org.jclouds.rackspace.cloudservers.options.ListOptions;
|
|||
import org.jclouds.rackspace.cloudservers.options.RebuildServerOptions;
|
||||
import org.jclouds.rest.config.RestModule;
|
||||
import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions;
|
||||
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||
import org.jclouds.util.Jsr330;
|
||||
|
@ -196,7 +200,7 @@ public class CloudServersClientTest {
|
|||
assertEquals(httpMethod.getHeaders().size(), 0);
|
||||
assertEquals(processor
|
||||
.createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(method).getClass(),
|
||||
ReturnFalseOn404.class);
|
||||
ReturnFalseOnNotFoundOr404.class);
|
||||
assertEquals(processor.createResponseParser(method, httpMethod).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
}
|
||||
|
@ -272,7 +276,7 @@ public class CloudServersClientTest {
|
|||
ParseServerFromJsonResponse.class);
|
||||
assertEquals(processor
|
||||
.createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(method).getClass(),
|
||||
MapHttp4xxCodesToExceptions.class);
|
||||
ReturnNullOnNotFoundOr404.class);
|
||||
}
|
||||
|
||||
public void testListFlavors() throws SecurityException, NoSuchMethodException {
|
||||
|
@ -363,7 +367,7 @@ public class CloudServersClientTest {
|
|||
ParseFlavorFromJsonResponse.class);
|
||||
assertEquals(processor
|
||||
.createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(method).getClass(),
|
||||
MapHttp4xxCodesToExceptions.class);
|
||||
ReturnNullOnNotFoundOr404.class);
|
||||
}
|
||||
|
||||
public void testListImages() throws SecurityException, NoSuchMethodException {
|
||||
|
@ -454,7 +458,7 @@ public class CloudServersClientTest {
|
|||
ParseImageFromJsonResponse.class);
|
||||
assertEquals(processor
|
||||
.createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(method).getClass(),
|
||||
MapHttp4xxCodesToExceptions.class);
|
||||
ReturnNullOnNotFoundOr404.class);
|
||||
}
|
||||
|
||||
public void testDeleteServer() throws SecurityException, NoSuchMethodException {
|
||||
|
@ -468,7 +472,7 @@ public class CloudServersClientTest {
|
|||
assertEquals(httpMethod.getHeaders().size(), 0);
|
||||
assertEquals(processor
|
||||
.createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(method).getClass(),
|
||||
ReturnFalseOn404.class);
|
||||
ReturnFalseOnNotFoundOr404.class);
|
||||
assertEquals(processor.createResponseParser(method, httpMethod).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
}
|
||||
|
@ -492,9 +496,9 @@ public class CloudServersClientTest {
|
|||
assertEquals("{\"shareIp\":{\"sharedIpGroupId\":3}}", httpMethod.getPayload().getRawContent());
|
||||
assertEquals(processor
|
||||
.createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(method).getClass(),
|
||||
ReturnFalseOn404.class);
|
||||
MapHttp4xxCodesToExceptions.class);
|
||||
assertEquals(processor.createResponseParser(method, httpMethod).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
CloseContentAndReturn.class);
|
||||
}
|
||||
|
||||
public void testShareIpConfig() throws SecurityException, NoSuchMethodException,
|
||||
|
@ -517,9 +521,9 @@ public class CloudServersClientTest {
|
|||
.getPayload().getRawContent());
|
||||
assertEquals(processor
|
||||
.createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(method).getClass(),
|
||||
ReturnFalseOn404.class);
|
||||
MapHttp4xxCodesToExceptions.class);
|
||||
assertEquals(processor.createResponseParser(method, httpMethod).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
CloseContentAndReturn.class);
|
||||
}
|
||||
|
||||
public void testUnshareIpNoConfig() throws SecurityException, NoSuchMethodException,
|
||||
|
@ -535,9 +539,9 @@ public class CloudServersClientTest {
|
|||
assertEquals(httpMethod.getHeaders().size(), 0);
|
||||
assertEquals(processor
|
||||
.createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(method).getClass(),
|
||||
ReturnFalseOn404.class);
|
||||
ReturnVoidOnNotFoundOr404.class);
|
||||
assertEquals(processor.createResponseParser(method, httpMethod).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
CloseContentAndReturn.class);
|
||||
}
|
||||
|
||||
public void testReplaceBackupSchedule() throws SecurityException, NoSuchMethodException {
|
||||
|
@ -562,7 +566,7 @@ public class CloudServersClientTest {
|
|||
.createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(method).getClass(),
|
||||
ReturnFalseOn404.class);
|
||||
assertEquals(processor.createResponseParser(method, httpMethod).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
CloseContentAndReturn.class);
|
||||
}
|
||||
|
||||
public void testDeleteBackupSchedule() throws SecurityException, NoSuchMethodException {
|
||||
|
@ -576,7 +580,7 @@ public class CloudServersClientTest {
|
|||
assertEquals(httpMethod.getHeaders().size(), 0);
|
||||
assertEquals(processor
|
||||
.createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(method).getClass(),
|
||||
ReturnFalseOn404.class);
|
||||
ReturnFalseOnNotFoundOr404.class);
|
||||
assertEquals(processor.createResponseParser(method, httpMethod).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
}
|
||||
|
@ -599,9 +603,9 @@ public class CloudServersClientTest {
|
|||
assertEquals("{\"server\":{\"adminPass\":\"foo\"}}", httpMethod.getPayload().getRawContent());
|
||||
assertEquals(processor
|
||||
.createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(method).getClass(),
|
||||
ReturnFalseOn404.class);
|
||||
MapHttp4xxCodesToExceptions.class);
|
||||
assertEquals(processor.createResponseParser(method, httpMethod).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
CloseContentAndReturn.class);
|
||||
}
|
||||
|
||||
public void testChangeServerName() throws SecurityException, NoSuchMethodException {
|
||||
|
@ -622,9 +626,9 @@ public class CloudServersClientTest {
|
|||
assertEquals("{\"server\":{\"name\":\"foo\"}}", httpMethod.getPayload().getRawContent());
|
||||
assertEquals(processor
|
||||
.createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(method).getClass(),
|
||||
ReturnFalseOn404.class);
|
||||
MapHttp4xxCodesToExceptions.class);
|
||||
assertEquals(processor.createResponseParser(method, httpMethod).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
CloseContentAndReturn.class);
|
||||
}
|
||||
|
||||
public void testListSharedIpGroups() throws SecurityException, NoSuchMethodException {
|
||||
|
@ -716,7 +720,7 @@ public class CloudServersClientTest {
|
|||
ParseSharedIpGroupFromJsonResponse.class);
|
||||
assertEquals(processor
|
||||
.createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(method).getClass(),
|
||||
MapHttp4xxCodesToExceptions.class);
|
||||
ReturnNullOnNotFoundOr404.class);
|
||||
}
|
||||
|
||||
private static final Class<? extends CreateSharedIpGroupOptions[]> createSharedIpGroupOptionsVarargsClass = new CreateSharedIpGroupOptions[] {}
|
||||
|
@ -776,13 +780,13 @@ public class CloudServersClientTest {
|
|||
assertEquals(httpMethod.getHeaders().size(), 0);
|
||||
assertEquals(processor
|
||||
.createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(method).getClass(),
|
||||
ReturnFalseOn404.class);
|
||||
ReturnFalseOnNotFoundOr404.class);
|
||||
assertEquals(processor.createResponseParser(method, httpMethod).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
}
|
||||
|
||||
public void testListAddresses() throws SecurityException, NoSuchMethodException {
|
||||
Method method = CloudServersAsyncClient.class.getMethod("listAddresses", int.class);
|
||||
Method method = CloudServersAsyncClient.class.getMethod("getAddresses", int.class);
|
||||
|
||||
GeneratedHttpRequest<CloudServersAsyncClient> httpMethod = processor.createRequest(method,
|
||||
new Object[] { 2 });
|
||||
|
@ -824,7 +828,7 @@ public class CloudServersClientTest {
|
|||
}
|
||||
|
||||
public void testListBackupSchedule() throws SecurityException, NoSuchMethodException {
|
||||
Method method = CloudServersAsyncClient.class.getMethod("listBackupSchedule", int.class);
|
||||
Method method = CloudServersAsyncClient.class.getMethod("getBackupSchedule", int.class);
|
||||
|
||||
GeneratedHttpRequest<CloudServersAsyncClient> httpMethod = processor.createRequest(method,
|
||||
new Object[] { 2 });
|
||||
|
@ -899,9 +903,9 @@ public class CloudServersClientTest {
|
|||
.singletonList(MediaType.APPLICATION_JSON));
|
||||
assertEquals(processor
|
||||
.createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(method).getClass(),
|
||||
ReturnFalseOn404.class);
|
||||
MapHttp4xxCodesToExceptions.class);
|
||||
assertEquals(processor.createResponseParser(method, httpMethod).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
CloseContentAndReturn.class);
|
||||
assertNotNull(processor.getMapPayloadBinderOrNull(method, new Object[] { "",
|
||||
new RebuildServerOptions[] { withImage(2) } }));
|
||||
}
|
||||
|
@ -924,9 +928,9 @@ public class CloudServersClientTest {
|
|||
assertEquals("{\"reboot\":{\"type\":\"HARD\"}}", httpMethod.getPayload().getRawContent());
|
||||
assertEquals(processor
|
||||
.createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(method).getClass(),
|
||||
ReturnFalseOn404.class);
|
||||
MapHttp4xxCodesToExceptions.class);
|
||||
assertEquals(processor.createResponseParser(method, httpMethod).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
CloseContentAndReturn.class);
|
||||
}
|
||||
|
||||
public void testResize() throws SecurityException, NoSuchMethodException {
|
||||
|
@ -946,9 +950,9 @@ public class CloudServersClientTest {
|
|||
assertEquals("{\"resize\":{\"flavorId\":3}}", httpMethod.getPayload().getRawContent());
|
||||
assertEquals(processor
|
||||
.createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(method).getClass(),
|
||||
ReturnFalseOn404.class);
|
||||
MapHttp4xxCodesToExceptions.class);
|
||||
assertEquals(processor.createResponseParser(method, httpMethod).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
CloseContentAndReturn.class);
|
||||
}
|
||||
|
||||
public void testConfirmResize() throws SecurityException, NoSuchMethodException {
|
||||
|
@ -968,9 +972,9 @@ public class CloudServersClientTest {
|
|||
assertEquals("{\"confirmResize\":null}", httpMethod.getPayload().getRawContent());
|
||||
assertEquals(processor
|
||||
.createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(method).getClass(),
|
||||
ReturnFalseOn404.class);
|
||||
MapHttp4xxCodesToExceptions.class);
|
||||
assertEquals(processor.createResponseParser(method, httpMethod).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
CloseContentAndReturn.class);
|
||||
}
|
||||
|
||||
public void testRevertResize() throws SecurityException, NoSuchMethodException {
|
||||
|
@ -989,9 +993,9 @@ public class CloudServersClientTest {
|
|||
assertEquals("{\"revertResize\":null}", httpMethod.getPayload().getRawContent());
|
||||
assertEquals(processor
|
||||
.createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(method).getClass(),
|
||||
ReturnFalseOn404.class);
|
||||
MapHttp4xxCodesToExceptions.class);
|
||||
assertEquals(processor.createResponseParser(method, httpMethod).getClass(),
|
||||
ReturnTrueIf2xx.class);
|
||||
CloseContentAndReturn.class);
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
|
@ -1000,7 +1004,7 @@ public class CloudServersClientTest {
|
|||
@Override
|
||||
protected void configure() {
|
||||
Jsr330.bindProperties(this.binder(), new RackspacePropertiesBuilder("user", "key")
|
||||
.build());
|
||||
.build());
|
||||
bind(URI.class).annotatedWith(CloudServers.class).toInstance(
|
||||
URI.create("http://localhost:8080"));
|
||||
bind(Logger.LoggerFactory.class).toInstance(new LoggerFactory() {
|
||||
|
|
|
@ -60,7 +60,6 @@ public class CloudServersComputeServiceLiveTest extends BaseComputeServiceLiveTe
|
|||
@SuppressWarnings("unused")
|
||||
RestContext<CloudServersAsyncClient, CloudServersClient> tmContext = new ComputeServiceContextFactory()
|
||||
.createContext(service, user, password).getProviderSpecificContext();
|
||||
|
||||
CloudServersComputeService.class.cast(client);
|
||||
}
|
||||
}
|
|
@ -20,179 +20,84 @@ 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;
|
||||
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.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.NodeMetadataImpl;
|
||||
import org.jclouds.compute.domain.internal.NodeSetImpl;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.compute.internal.BaseComputeService;
|
||||
import org.jclouds.compute.util.ComputeUtils;
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.rimuhosting.miro.RimuHostingClient;
|
||||
import org.jclouds.rimuhosting.miro.domain.NewServerResponse;
|
||||
import org.jclouds.rimuhosting.miro.domain.Server;
|
||||
import org.jclouds.rimuhosting.miro.domain.internal.RunningState;
|
||||
|
||||
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 {
|
||||
public class RimuHostingComputeService extends BaseComputeService {
|
||||
|
||||
@VisibleForTesting
|
||||
static Iterable<InetAddress> getPublicAddresses(Server server) {
|
||||
Iterable<String> addresses = Iterables.concat(ImmutableList.of(server.getIpAddresses()
|
||||
.getPrimaryIp()), server.getIpAddresses().getSecondaryIps());
|
||||
return Iterables.transform(addresses, new Function<String, InetAddress>() {
|
||||
|
||||
@Override
|
||||
public InetAddress apply(String from) {
|
||||
try {
|
||||
return InetAddress.getByName(from);
|
||||
} catch (UnknownHostException e) {
|
||||
// TODO: log the failure.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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 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;
|
||||
protected final String nodeNamingConvention;
|
||||
private final ComputeUtils utils;
|
||||
private final ServerToNodeMetadata serverToNodeMetadata;
|
||||
protected final ExecutorService executor;
|
||||
private final Function<Server, NodeMetadata> serverToNodeMetadata;
|
||||
private final Map<RunningState, NodeState> runningStateToNodeState;
|
||||
private final Predicate<Server> serverRunning;
|
||||
private final Predicate<Server> serverDestroyed;
|
||||
private final Function<Server, Iterable<InetAddress>> getPublicAddresses;
|
||||
|
||||
@Inject
|
||||
public RimuHostingComputeService(RimuHostingClient client,
|
||||
Provider<TemplateBuilder> templateBuilderProvider,
|
||||
public RimuHostingComputeService(Provider<TemplateBuilder> templateBuilderProvider,
|
||||
Provider<Map<String, ? extends Image>> images,
|
||||
Provider<Map<String, ? extends Size>> sizes, ServerToNodeMetadata serverToNodeMetadata,
|
||||
Provider<Map<String, ? extends Size>> sizes,
|
||||
Provider<Map<String, ? extends Location>> locations, ComputeUtils utils,
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
|
||||
RimuHostingClient client, Map<RunningState, NodeState> runningStateToNodeState,
|
||||
@Named("RUNNING") Predicate<Server> serverRunning,
|
||||
@Named("DESTROYED") Predicate<Server> serverDestroyed,
|
||||
Function<Server, NodeMetadata> serverToNodeMetadata,
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor,
|
||||
Function<Server, Iterable<InetAddress>> getPublicAddresses) {
|
||||
super(images, sizes, locations, templateBuilderProvider, "%s-%d", utils, executor);
|
||||
this.client = client;
|
||||
this.images = images;
|
||||
this.sizes = sizes;
|
||||
this.locations = locations;
|
||||
this.utils = utils;
|
||||
this.templateBuilderProvider = templateBuilderProvider;
|
||||
this.runningStateToNodeState = runningStateToNodeState;
|
||||
this.serverRunning = serverRunning;
|
||||
this.serverDestroyed = serverDestroyed;
|
||||
this.serverToNodeMetadata = serverToNodeMetadata;
|
||||
this.executor = executor;
|
||||
this.nodeNamingConvention = "%s-%d";
|
||||
this.getPublicAddresses = getPublicAddresses;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeSet runNodesWithTag(final String tag, int count, final Template template) {
|
||||
checkArgument(tag.indexOf('-') == -1, "tag cannot contain hyphens");
|
||||
checkNotNull(template.getLocation(), "location");
|
||||
final Set<NodeMetadata> nodes = Sets.newHashSet();
|
||||
int nodesToStart = count;
|
||||
int i = 0;
|
||||
while (nodesToStart > 0) {
|
||||
int currentCount = i;
|
||||
Map<String, ListenableFuture<Void>> responses = Maps.newHashMap();
|
||||
for (; i < currentCount + nodesToStart; i++) {
|
||||
final String name = String.format(nodeNamingConvention, tag, i + 1);
|
||||
responses.put(name, makeListenable(executor.submit(new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
NodeMetadata node = null;
|
||||
try {
|
||||
node = startServerAndConvertToNode(tag, name, template);
|
||||
logger.debug("<< running server(%s)", node.getId());
|
||||
utils.runOptionsOnNode(node, template.getOptions());
|
||||
logger.debug("<< options applied server(%s)", node.getId());
|
||||
nodes.add(node);
|
||||
} catch (Exception e) {
|
||||
if (node != null) {
|
||||
destroyNode(node);
|
||||
logger.error(e, "<< error applying server(%s) [%s] destroying ", name, e
|
||||
.getMessage());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}), executor));
|
||||
}
|
||||
nodesToStart = awaitCompletion(responses, executor, null, logger, "nodes").size();
|
||||
}
|
||||
return new NodeSetImpl(nodes);
|
||||
}
|
||||
|
||||
private NodeMetadata startServerAndConvertToNode(final String tag, final String name,
|
||||
final Template template) {
|
||||
protected NodeMetadata startNode(final String tag, final String name, final Template template) {
|
||||
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..
|
||||
serverRunning.apply(serverResponse.getServer());
|
||||
Server server = client.getServer(serverResponse.getServer().getId());
|
||||
// we have to lookup the new details in order to retrieve the currently assigned ip address.
|
||||
NodeMetadata node = new NodeMetadataImpl(server.getId().toString(), name, template
|
||||
.getLocation().getId(), null, ImmutableMap.<String, String> of(), tag,
|
||||
runningStateToNodeState.get(server.getState()), getPublicAddresses.apply(server),
|
||||
ImmutableList.<InetAddress> of(), ImmutableMap.<String, String> of(),
|
||||
new Credentials("root", serverResponse.getNewInstanceRequest().getCreateOptions()
|
||||
.getPassword()));
|
||||
|
@ -204,126 +109,21 @@ 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 serverToNodeMetadata.apply(client.getServer(Long.parseLong(node.getId())));
|
||||
long serverId = Long.parseLong(node.getId());
|
||||
Server server = client.getServer(serverId);
|
||||
return server == null ? null : serverToNodeMetadata.apply(server);
|
||||
}
|
||||
|
||||
@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");
|
||||
|
||||
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);
|
||||
}
|
||||
protected Iterable<NodeMetadata> doGetNodes() {
|
||||
return Iterables.transform(client.getServerList(), serverToNodeMetadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends ComputeMetadata> getNodes() {
|
||||
logger.debug(">> listing servers");
|
||||
ImmutableMap<String, NodeMetadata> map = doGetNodes();
|
||||
logger.debug("<< list(%d)", map.size());
|
||||
return map;
|
||||
protected boolean doDestroyNode(ComputeMetadata node) {
|
||||
long serverId = Long.parseLong(node.getId());
|
||||
client.destroyServer(serverId);
|
||||
return serverDestroyed.apply(client.getServer(serverId));
|
||||
}
|
||||
|
||||
private ImmutableMap<String, NodeMetadata> doGetNodes() {
|
||||
ImmutableMap<String, NodeMetadata> map = Maps.uniqueIndex(Iterables.transform(client
|
||||
.getServerList(), serverToNodeMetadata), METADATA_TO_ID);
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyNodesWithTag(String tag) { // TODO parallel
|
||||
logger.debug(">> terminating servers by tag(%s)", tag);
|
||||
Iterable<NodeMetadata> nodesToDestroy = Iterables.filter(doGetNodes(tag),
|
||||
new Predicate<NodeMetadata>() {
|
||||
@Override
|
||||
public boolean apply(NodeMetadata input) {
|
||||
return input.getState() != NodeState.TERMINATED;
|
||||
|
||||
}
|
||||
});
|
||||
Map<NodeMetadata, ListenableFuture<Void>> responses = Maps.newHashMap();
|
||||
for (final NodeMetadata node : nodesToDestroy) {
|
||||
responses.put(node, 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 getNodesWithTag(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 Map<String, ? extends Image> getImages() {
|
||||
return images.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemplateBuilder templateBuilder() {
|
||||
return templateBuilderProvider.get();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,6 +18,8 @@
|
|||
*/
|
||||
package org.jclouds.rimuhosting.miro.compute.config;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
@ -28,6 +30,7 @@ import java.util.regex.Matcher;
|
|||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
|
@ -37,13 +40,17 @@ 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.NodeMetadata;
|
||||
import org.jclouds.compute.domain.NodeState;
|
||||
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.NodeMetadataImpl;
|
||||
import org.jclouds.compute.domain.internal.SizeImpl;
|
||||
import org.jclouds.compute.internal.ComputeServiceContextImpl;
|
||||
import org.jclouds.compute.predicates.RunScriptRunning;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.domain.LocationScope;
|
||||
import org.jclouds.domain.internal.LocationImpl;
|
||||
|
@ -55,16 +62,21 @@ import org.jclouds.rimuhosting.miro.RimuHostingClient;
|
|||
import org.jclouds.rimuhosting.miro.compute.RimuHostingComputeService;
|
||||
import org.jclouds.rimuhosting.miro.config.RimuHostingContextModule;
|
||||
import org.jclouds.rimuhosting.miro.domain.PricingPlan;
|
||||
import org.jclouds.rimuhosting.miro.domain.Server;
|
||||
import org.jclouds.rimuhosting.miro.domain.internal.RunningState;
|
||||
import org.jclouds.ssh.SshClient;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
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;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
/**
|
||||
* Configures the {@link RimuHostingComputeServiceContext}; requires
|
||||
|
@ -78,6 +90,69 @@ public class RimuHostingComputeServiceContextModule extends RimuHostingContextMo
|
|||
protected void configure() {
|
||||
super.configure();
|
||||
bind(ComputeService.class).to(RimuHostingComputeService.class).asEagerSingleton();
|
||||
bind(new TypeLiteral<Function<Server, NodeMetadata>>() {
|
||||
}).to(ServerToNodeMetadata.class);
|
||||
bind(new TypeLiteral<Function<Server, Iterable<InetAddress>>>() {
|
||||
}).to(ServerToPublicAddresses.class);
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
Map<RunningState, NodeState> provideServerToNodeState() {
|
||||
return ImmutableMap.<RunningState, NodeState> builder().put(RunningState.RUNNING,
|
||||
NodeState.RUNNING)//
|
||||
.put(RunningState.NOTRUNNING, NodeState.SUSPENDED)//
|
||||
.put(RunningState.POWERCYCLING, NodeState.PENDING)//
|
||||
.put(RunningState.RESTARTING, NodeState.PENDING)//
|
||||
.build();
|
||||
}
|
||||
|
||||
@Singleton
|
||||
private static class ServerToNodeMetadata implements Function<Server, NodeMetadata> {
|
||||
private final Function<Server, Iterable<InetAddress>> getPublicAddresses;
|
||||
private final Map<RunningState, NodeState> runningStateToNodeState;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Inject
|
||||
ServerToNodeMetadata(Function<Server, Iterable<InetAddress>> getPublicAddresses,
|
||||
Map<RunningState, NodeState> runningStateToNodeState) {
|
||||
this.getPublicAddresses = getPublicAddresses;
|
||||
this.runningStateToNodeState = runningStateToNodeState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeMetadata apply(Server from) {
|
||||
String locationId = "//TODO";
|
||||
String tag = from.getName().replaceAll("-[0-9]+", "");
|
||||
Credentials creds = null;
|
||||
NodeState state = runningStateToNodeState.get(from.getState());
|
||||
return new NodeMetadataImpl(from.getId() + "", from.getName(), locationId, null,
|
||||
ImmutableMap.<String, String> of(), tag, state, getPublicAddresses.apply(from),
|
||||
ImmutableList.<InetAddress> of(), ImmutableMap.<String, String> of(), creds);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Singleton
|
||||
private static class ServerToPublicAddresses implements Function<Server, Iterable<InetAddress>> {
|
||||
@Override
|
||||
public Iterable<InetAddress> apply(Server server) {
|
||||
Iterable<String> addresses = server.getIpAddresses() == null ? ImmutableSet.<String> of()
|
||||
: Iterables.concat(ImmutableList.of(server.getIpAddresses().getPrimaryIp()),
|
||||
server.getIpAddresses().getSecondaryIps());
|
||||
return Iterables.transform(addresses, new Function<String, InetAddress>() {
|
||||
|
||||
@Override
|
||||
public InetAddress apply(String from) {
|
||||
try {
|
||||
return InetAddress.getByName(from);
|
||||
} catch (UnknownHostException e) {
|
||||
// TODO: log the failure.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
@ -199,4 +274,5 @@ public class RimuHostingComputeServiceContextModule extends RimuHostingContextMo
|
|||
holder.logger.debug("<< images(%d)", images.size());
|
||||
return Maps.uniqueIndex(images, indexer);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,9 +18,14 @@
|
|||
*/
|
||||
package org.jclouds.rimuhosting.miro.config;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.concurrent.internal.SyncProxy;
|
||||
import org.jclouds.http.RequiresHttp;
|
||||
import org.jclouds.predicates.RetryablePredicate;
|
||||
|
@ -30,15 +35,15 @@ import org.jclouds.rest.RestClientFactory;
|
|||
import org.jclouds.rimuhosting.miro.RimuHosting;
|
||||
import org.jclouds.rimuhosting.miro.RimuHostingAsyncClient;
|
||||
import org.jclouds.rimuhosting.miro.RimuHostingClient;
|
||||
import org.jclouds.rimuhosting.miro.domain.Server;
|
||||
import org.jclouds.rimuhosting.miro.filters.RimuHostingAuthentication;
|
||||
import org.jclouds.rimuhosting.miro.predicates.ServerDestroyed;
|
||||
import org.jclouds.rimuhosting.miro.predicates.ServerRunning;
|
||||
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;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
|
||||
/**
|
||||
* Configures the RimuHosting connection.
|
||||
|
@ -49,6 +54,20 @@ import java.util.concurrent.TimeUnit;
|
|||
@ConfiguresRestClient
|
||||
public class RimuHostingRestClientModule extends AbstractModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("RUNNING")
|
||||
protected Predicate<Server> serverRunning(ServerRunning stateRunning) {
|
||||
return new RetryablePredicate<Server>(stateRunning, 600, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("DESTROYED")
|
||||
protected Predicate<Server> serverDeleted(ServerDestroyed stateDeleted) {
|
||||
return new RetryablePredicate<Server>(stateDeleted, 600, 50, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected Predicate<InetSocketAddress> socketTester(SocketOpen open) {
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.jclouds.rimuhosting.miro.domain;
|
|||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import org.jclouds.rimuhosting.miro.data.NewServerData;
|
||||
import org.jclouds.rimuhosting.miro.domain.internal.RunningState;
|
||||
|
||||
/**
|
||||
* Instance Object.
|
||||
|
@ -50,7 +51,7 @@ public class Server implements Comparable<Server> {
|
|||
@SerializedName("order_oid")
|
||||
private Long id;
|
||||
@SerializedName("running_state")
|
||||
private String state;
|
||||
private RunningState state;
|
||||
@SerializedName("server_type")
|
||||
private String type;
|
||||
private String slug;
|
||||
|
@ -133,11 +134,11 @@ public class Server implements Comparable<Server> {
|
|||
this.id = id;
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
public RunningState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(String state) {
|
||||
public void setState(RunningState state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
package org.jclouds.rimuhosting.miro.predicates;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.rimuhosting.miro.RimuHostingClient;
|
||||
import org.jclouds.rimuhosting.miro.domain.Server;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
*
|
||||
* Tests to see if a task succeeds.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class ServerDestroyed implements Predicate<Server> {
|
||||
|
||||
private final RimuHostingClient client;
|
||||
|
||||
@Resource
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
@Inject
|
||||
public ServerDestroyed(RimuHostingClient client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public boolean apply(Server server) {
|
||||
server = refresh(server);
|
||||
if (server == null)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private Server refresh(Server server) {
|
||||
return client.getServer(server.getId());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package org.jclouds.rimuhosting.miro.predicates;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.rimuhosting.miro.RimuHostingClient;
|
||||
import org.jclouds.rimuhosting.miro.domain.Server;
|
||||
import org.jclouds.rimuhosting.miro.domain.internal.RunningState;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
*
|
||||
* Tests to see if a task succeeds.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class ServerRunning implements Predicate<Server> {
|
||||
|
||||
private final RimuHostingClient client;
|
||||
|
||||
@Resource
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
@Inject
|
||||
public ServerRunning(RimuHostingClient client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public boolean apply(Server server) {
|
||||
logger.trace("looking for state on server %s", checkNotNull(server, "server"));
|
||||
server = refresh(server);
|
||||
if (server == null)
|
||||
return false;
|
||||
logger.trace("%s: looking for server state %s: currently: %s", server.getId(),
|
||||
RunningState.RUNNING, server.getState());
|
||||
return server.getState() == RunningState.RUNNING;
|
||||
}
|
||||
|
||||
private Server refresh(Server server) {
|
||||
return client.getServer(server.getId());
|
||||
}
|
||||
}
|
|
@ -189,7 +189,7 @@ public class ComputeTask extends Task {
|
|||
Template template = createTemplateFromElement(nodeElement, computeService);
|
||||
|
||||
for (NodeMetadata createdNode : computeService.runNodesWithTag(tag, nodeElement.getCount(),
|
||||
template)) {
|
||||
template).values()) {
|
||||
logDetails(computeService, createdNode);
|
||||
addNodeDetailsAsProjectProperties(createdNode);
|
||||
}
|
||||
|
@ -216,7 +216,7 @@ public class ComputeTask extends Task {
|
|||
|
||||
private void get(ComputeService computeService) {
|
||||
log(String.format("get tag: %s", nodeElement.getTag()));
|
||||
for (ComputeMetadata node : computeService.getNodesWithTag(nodeElement.getTag())) {
|
||||
for (ComputeMetadata node : computeService.getNodesWithTag(nodeElement.getTag()).values()) {
|
||||
logDetails(computeService, node);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,11 +37,14 @@ import javax.ws.rs.PathParam;
|
|||
import javax.ws.rs.Produces;
|
||||
|
||||
import org.jclouds.rest.annotations.Endpoint;
|
||||
import org.jclouds.rest.annotations.ExceptionParser;
|
||||
import org.jclouds.rest.annotations.MapBinder;
|
||||
import org.jclouds.rest.annotations.MapPayloadParam;
|
||||
import org.jclouds.rest.annotations.ParamParser;
|
||||
import org.jclouds.rest.annotations.RequestFilters;
|
||||
import org.jclouds.rest.annotations.XMLResponseParser;
|
||||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.vcloud.binders.BindCloneVAppParamsToXmlPayload;
|
||||
import org.jclouds.vcloud.binders.BindInstantiateVAppTemplateParamsToXmlPayload;
|
||||
import org.jclouds.vcloud.domain.Catalog;
|
||||
|
@ -86,46 +89,53 @@ public interface VCloudAsyncClient {
|
|||
@Consumes(ORG_XML)
|
||||
@XMLResponseParser(OrgHandler.class)
|
||||
ListenableFuture<? extends Organization> getDefaultOrganization();
|
||||
|
||||
|
||||
@GET
|
||||
@Endpoint(org.jclouds.vcloud.endpoints.VCloudApi.class)
|
||||
@Path("/org/{orgId}")
|
||||
@XMLResponseParser(OrgHandler.class)
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
@Consumes(ORG_XML)
|
||||
ListenableFuture<? extends Organization> getOrganization(@PathParam("orgId") String orgId);
|
||||
|
||||
|
||||
@GET
|
||||
@Endpoint(org.jclouds.vcloud.endpoints.Catalog.class)
|
||||
@Consumes(CATALOG_XML)
|
||||
@XMLResponseParser(CatalogHandler.class)
|
||||
ListenableFuture<? extends Catalog> getDefaultCatalog();
|
||||
|
||||
|
||||
@GET
|
||||
@Endpoint(org.jclouds.vcloud.endpoints.VCloudApi.class)
|
||||
@Path("/catalog/{catalogId}")
|
||||
@XMLResponseParser(CatalogHandler.class)
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
@Consumes(CATALOG_XML)
|
||||
ListenableFuture<? extends Catalog> getCatalog(@PathParam("catalogId") String catalogId);
|
||||
|
||||
|
||||
@GET
|
||||
@Endpoint(org.jclouds.vcloud.endpoints.VCloudApi.class)
|
||||
@Path("/vAppTemplate/{vAppTemplateId}")
|
||||
@Consumes(VAPPTEMPLATE_XML)
|
||||
@XMLResponseParser(VAppTemplateHandler.class)
|
||||
ListenableFuture<? extends VAppTemplate> getVAppTemplate(@PathParam("vAppTemplateId") String vAppTemplateId);
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
ListenableFuture<? extends VAppTemplate> getVAppTemplate(
|
||||
@PathParam("vAppTemplateId") String vAppTemplateId);
|
||||
|
||||
@GET
|
||||
@Endpoint(org.jclouds.vcloud.endpoints.VCloudApi.class)
|
||||
@Path("/catalogItem/{catalogItemId}")
|
||||
@Consumes(CATALOGITEM_XML)
|
||||
@XMLResponseParser(CatalogItemHandler.class)
|
||||
ListenableFuture<? extends CatalogItem> getCatalogItem(@PathParam("catalogItemId") String catalogItemId);
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
ListenableFuture<? extends CatalogItem> getCatalogItem(
|
||||
@PathParam("catalogItemId") String catalogItemId);
|
||||
|
||||
@GET
|
||||
@Endpoint(org.jclouds.vcloud.endpoints.VCloudApi.class)
|
||||
@Path("/network/{networkId}")
|
||||
@Consumes(NETWORK_XML)
|
||||
@XMLResponseParser(NetworkHandler.class)
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
ListenableFuture<? extends Network> getNetwork(@PathParam("networkId") String networkId);
|
||||
|
||||
@GET
|
||||
|
@ -139,6 +149,7 @@ public interface VCloudAsyncClient {
|
|||
@Path("/vdc/{vDCId}")
|
||||
@XMLResponseParser(VDCHandler.class)
|
||||
@Consumes(VDC_XML)
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
ListenableFuture<? extends VDC> getVDC(@PathParam("vDCId") String vDCId);
|
||||
|
||||
@GET
|
||||
|
@ -146,6 +157,7 @@ public interface VCloudAsyncClient {
|
|||
@Path("/tasksList/{tasksListId}")
|
||||
@Consumes(TASKSLIST_XML)
|
||||
@XMLResponseParser(TasksListHandler.class)
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
ListenableFuture<? extends TasksList> getTasksList(@PathParam("tasksListId") String tasksListId);
|
||||
|
||||
@GET
|
||||
|
@ -163,6 +175,7 @@ public interface VCloudAsyncClient {
|
|||
|
||||
@DELETE
|
||||
@Endpoint(org.jclouds.vcloud.endpoints.VCloudApi.class)
|
||||
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
|
||||
@Path("/vApp/{vAppId}")
|
||||
ListenableFuture<Void> deleteVApp(@PathParam("vAppId") String vAppId);
|
||||
|
||||
|
@ -226,6 +239,7 @@ public interface VCloudAsyncClient {
|
|||
@Endpoint(org.jclouds.vcloud.endpoints.VCloudApi.class)
|
||||
@Path("/task/{taskId}")
|
||||
@XMLResponseParser(TaskHandler.class)
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
ListenableFuture<? extends Task> getTask(@PathParam("taskId") String taskId);
|
||||
|
||||
@POST
|
||||
|
@ -238,6 +252,7 @@ public interface VCloudAsyncClient {
|
|||
@Endpoint(org.jclouds.vcloud.endpoints.VCloudApi.class)
|
||||
@Path("/vApp/{vAppId}")
|
||||
@XMLResponseParser(VAppHandler.class)
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
ListenableFuture<? extends VApp> getVApp(@PathParam("vAppId") String appId);
|
||||
|
||||
@POST
|
||||
|
|
|
@ -21,18 +21,13 @@ 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;
|
||||
|
@ -43,18 +38,15 @@ import org.jclouds.compute.domain.ComputeMetadata;
|
|||
import org.jclouds.compute.domain.ComputeType;
|
||||
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.NodeMetadataImpl;
|
||||
import org.jclouds.compute.domain.internal.NodeSetImpl;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.compute.internal.BaseComputeService;
|
||||
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;
|
||||
import org.jclouds.vcloud.domain.NamedResource;
|
||||
|
@ -63,117 +55,43 @@ 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;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class VCloudComputeService implements ComputeService, VCloudComputeClient {
|
||||
public class VCloudComputeService extends BaseComputeService 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<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 String nodeNamingConvention;
|
||||
protected final ComputeUtils utils;
|
||||
protected final VCloudClient client;
|
||||
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(
|
||||
VAppStatus.ON, NodeState.RUNNING).put(VAppStatus.RESOLVED, NodeState.PENDING)
|
||||
.put(VAppStatus.SUSPENDED, NodeState.SUSPENDED).put(VAppStatus.UNRESOLVED,
|
||||
NodeState.PENDING).build();
|
||||
protected final Map<VAppStatus, NodeState> vAppStatusToNodeState;
|
||||
|
||||
@Inject
|
||||
public VCloudComputeService(VCloudClient client,
|
||||
Provider<TemplateBuilder> templateBuilderProvider,
|
||||
public VCloudComputeService(Provider<TemplateBuilder> templateBuilderProvider,
|
||||
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,
|
||||
VCloudClient client, Predicate<String> successTester,
|
||||
@Named("NOT_FOUND") Predicate<VApp> notFoundTester,
|
||||
Map<VAppStatus, NodeState> vAppStatusToNodeState,
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
|
||||
this.taskTester = successTester;
|
||||
super(images, sizes, locations, templateBuilderProvider, "%s-%d", utils, executor);
|
||||
this.client = client;
|
||||
this.images = images;
|
||||
this.sizes = sizes;
|
||||
this.locations = locations;
|
||||
this.templateBuilderProvider = templateBuilderProvider;
|
||||
this.utils = utils;
|
||||
this.taskTester = successTester;
|
||||
this.notFoundTester = notFoundTester;
|
||||
this.executor = executor;
|
||||
this.nodeNamingConvention = "%s-%d";
|
||||
this.vAppStatusToNodeState = vAppStatusToNodeState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeSet runNodesWithTag(final String tag, int count, final Template template) {
|
||||
checkArgument(tag.indexOf('-') == -1, "tag cannot contain hyphens");
|
||||
checkNotNull(template.getLocation(), "location");
|
||||
final Set<NodeMetadata> nodes = Sets.newHashSet();
|
||||
int nodesToStart = count;
|
||||
int i = 0;
|
||||
while (nodesToStart > 0) {
|
||||
int currentCount = i;
|
||||
Map<String, ListenableFuture<Void>> responses = Maps.newHashMap();
|
||||
for (; i < currentCount + nodesToStart; i++) {
|
||||
final String name = String.format(nodeNamingConvention, tag, i + 1);
|
||||
responses.put(name, makeListenable(executor.submit(new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
NodeMetadata node = null;
|
||||
try {
|
||||
node = startServerAndConvertToNode(tag, name, template);
|
||||
logger.debug("<< running server(%s)", node.getId());
|
||||
utils.runOptionsOnNode(node, template.getOptions());
|
||||
logger.debug("<< options applied server(%s)", node.getId());
|
||||
nodes.add(node);
|
||||
} catch (Exception e) {
|
||||
if (node != null) {
|
||||
destroyNode(node);
|
||||
logger.error(e, "<< error applying server(%s) [%s] destroying ", name, e
|
||||
.getMessage());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}), executor));
|
||||
}
|
||||
nodesToStart = awaitCompletion(responses, executor, null, logger, "nodes").size();
|
||||
}
|
||||
return new NodeSetImpl(nodes);
|
||||
}
|
||||
|
||||
private NodeMetadata startServerAndConvertToNode(final String tag, final String name,
|
||||
final Template template) {
|
||||
protected NodeMetadata startNode(final String tag, final String name, final Template template) {
|
||||
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
|
||||
|
@ -186,8 +104,8 @@ public class VCloudComputeService implements ComputeService, VCloudComputeClient
|
|||
Map<String, String> metaMap, VApp vApp) {
|
||||
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(),
|
||||
.get(vApp.getStatus()), getPublicAddresses(vApp.getId()), vApp
|
||||
.getNetworkToAddresses().values(), ImmutableMap.<String, String> of(),
|
||||
new Credentials(metaMap.get("username"), metaMap.get("password")));
|
||||
}
|
||||
|
||||
|
@ -209,14 +127,7 @@ public class VCloudComputeService implements ComputeService, VCloudComputeClient
|
|||
}
|
||||
|
||||
@Override
|
||||
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() {
|
||||
protected Iterable<? extends ComputeMetadata> doGetNodes() {
|
||||
Set<ComputeMetadata> nodes = Sets.newHashSet();
|
||||
for (NamedResource vdc : client.getDefaultOrganization().getVDCs().values()) {
|
||||
for (NamedResource resource : client.getVDC(vdc.getId()).getResourceEntities().values()) {
|
||||
|
@ -225,29 +136,13 @@ public class VCloudComputeService implements ComputeService, VCloudComputeClient
|
|||
}
|
||||
}
|
||||
}
|
||||
return Maps.uniqueIndex(nodes, METADATA_TO_ID);
|
||||
return nodes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyNode(ComputeMetadata node) {
|
||||
checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not "
|
||||
+ node.getType());
|
||||
protected boolean doDestroyNode(ComputeMetadata node) {
|
||||
stop(checkNotNull(node.getId(), "node.id"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemplateBuilder templateBuilder() {
|
||||
return templateBuilderProvider.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends Size> getSizes() {
|
||||
return sizes.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends Image> getImages() {
|
||||
return images.get();
|
||||
return true;
|
||||
}
|
||||
|
||||
public Map<String, String> start(String vDCId, String name, String templateId, int minCores,
|
||||
|
@ -369,61 +264,4 @@ public class VCloudComputeService implements ComputeService, VCloudComputeClient
|
|||
return Sets.newHashSet(vApp.getNetworkToAddresses().values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyNodesWithTag(String tag) { // TODO parallel
|
||||
logger.debug(">> terminating servers by tag(%s)", tag);
|
||||
Iterable<NodeMetadata> nodesToDestroy = Iterables.filter(doGetNodes(tag),
|
||||
new Predicate<NodeMetadata>() {
|
||||
@Override
|
||||
public boolean apply(NodeMetadata input) {
|
||||
return input.getState() != NodeState.TERMINATED;
|
||||
|
||||
}
|
||||
});
|
||||
Map<NodeMetadata, ListenableFuture<Void>> responses = Maps.newHashMap();
|
||||
for (final NodeMetadata node : nodesToDestroy) {
|
||||
responses.put(node, 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 getNodesWithTag(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)));
|
||||
}
|
||||
}
|
|
@ -36,6 +36,7 @@ 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.NodeState;
|
||||
import org.jclouds.compute.domain.OsFamily;
|
||||
import org.jclouds.compute.domain.Size;
|
||||
import org.jclouds.compute.domain.internal.ImageImpl;
|
||||
|
@ -60,6 +61,7 @@ import org.jclouds.vcloud.config.VCloudContextModule;
|
|||
import org.jclouds.vcloud.domain.Catalog;
|
||||
import org.jclouds.vcloud.domain.CatalogItem;
|
||||
import org.jclouds.vcloud.domain.NamedResource;
|
||||
import org.jclouds.vcloud.domain.VAppStatus;
|
||||
import org.jclouds.vcloud.domain.VAppTemplate;
|
||||
import org.jclouds.vcloud.domain.VDC;
|
||||
|
||||
|
@ -82,6 +84,16 @@ import com.google.inject.Provides;
|
|||
*/
|
||||
public class VCloudComputeServiceContextModule extends VCloudContextModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
Map<VAppStatus, NodeState> provideVAppStatusToNodeState() {
|
||||
return ImmutableMap
|
||||
.<VAppStatus, NodeState> builder().put(VAppStatus.OFF, NodeState.TERMINATED).put(
|
||||
VAppStatus.ON, NodeState.RUNNING).put(VAppStatus.RESOLVED, NodeState.PENDING).put(
|
||||
VAppStatus.SUSPENDED, NodeState.SUSPENDED).put(VAppStatus.UNRESOLVED,
|
||||
NodeState.PENDING).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
super.configure();
|
||||
|
|
|
@ -37,6 +37,8 @@ import org.jclouds.http.functions.ParseSax;
|
|||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.logging.Logger.LoggerFactory;
|
||||
import org.jclouds.rest.RestClientTest;
|
||||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||
import org.jclouds.util.Jsr330;
|
||||
|
@ -189,7 +191,7 @@ public class VCloudAsyncClientTest extends RestClientTest<VCloudAsyncClient> {
|
|||
|
||||
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
|
||||
assertSaxResponseParserClassEquals(method, OrgHandler.class);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(httpMethod);
|
||||
}
|
||||
|
@ -219,7 +221,7 @@ public class VCloudAsyncClientTest extends RestClientTest<VCloudAsyncClient> {
|
|||
|
||||
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
|
||||
assertSaxResponseParserClassEquals(method, CatalogHandler.class);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(httpMethod);
|
||||
}
|
||||
|
@ -234,7 +236,7 @@ public class VCloudAsyncClientTest extends RestClientTest<VCloudAsyncClient> {
|
|||
|
||||
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
|
||||
assertSaxResponseParserClassEquals(method, NetworkHandler.class);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(httpMethod);
|
||||
}
|
||||
|
@ -249,7 +251,7 @@ public class VCloudAsyncClientTest extends RestClientTest<VCloudAsyncClient> {
|
|||
|
||||
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
|
||||
assertSaxResponseParserClassEquals(method, CatalogItemHandler.class);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(httpMethod);
|
||||
}
|
||||
|
@ -264,7 +266,7 @@ public class VCloudAsyncClientTest extends RestClientTest<VCloudAsyncClient> {
|
|||
|
||||
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
|
||||
assertSaxResponseParserClassEquals(method, VAppTemplateHandler.class);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(httpMethod);
|
||||
}
|
||||
|
@ -294,7 +296,7 @@ public class VCloudAsyncClientTest extends RestClientTest<VCloudAsyncClient> {
|
|||
|
||||
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
|
||||
assertSaxResponseParserClassEquals(method, VDCHandler.class);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(httpMethod);
|
||||
}
|
||||
|
@ -325,7 +327,7 @@ public class VCloudAsyncClientTest extends RestClientTest<VCloudAsyncClient> {
|
|||
|
||||
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
|
||||
assertSaxResponseParserClassEquals(method, TasksListHandler.class);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(httpMethod);
|
||||
}
|
||||
|
@ -355,7 +357,7 @@ public class VCloudAsyncClientTest extends RestClientTest<VCloudAsyncClient> {
|
|||
|
||||
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
|
||||
assertSaxResponseParserClassEquals(method, VAppHandler.class);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(httpMethod);
|
||||
}
|
||||
|
@ -385,7 +387,7 @@ public class VCloudAsyncClientTest extends RestClientTest<VCloudAsyncClient> {
|
|||
|
||||
assertResponseParserClassEquals(method, httpMethod, CloseContentAndReturn.class);
|
||||
assertSaxResponseParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnVoidOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(httpMethod);
|
||||
}
|
||||
|
@ -477,7 +479,7 @@ public class VCloudAsyncClientTest extends RestClientTest<VCloudAsyncClient> {
|
|||
|
||||
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
|
||||
assertSaxResponseParserClassEquals(method, TaskHandler.class);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(httpMethod);
|
||||
}
|
||||
|
|
|
@ -29,11 +29,13 @@ import javax.ws.rs.PathParam;
|
|||
import javax.ws.rs.Produces;
|
||||
|
||||
import org.jclouds.rest.annotations.Endpoint;
|
||||
import org.jclouds.rest.annotations.ExceptionParser;
|
||||
import org.jclouds.rest.annotations.MapBinder;
|
||||
import org.jclouds.rest.annotations.MapPayloadParam;
|
||||
import org.jclouds.rest.annotations.ParamParser;
|
||||
import org.jclouds.rest.annotations.RequestFilters;
|
||||
import org.jclouds.rest.annotations.XMLResponseParser;
|
||||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||
import org.jclouds.vcloud.VCloudAsyncClient;
|
||||
import org.jclouds.vcloud.binders.BindInstantiateVAppTemplateParamsToXmlPayload;
|
||||
import org.jclouds.vcloud.domain.Catalog;
|
||||
|
@ -70,6 +72,7 @@ public interface HostingDotComVCloudAsyncClient extends VCloudAsyncClient {
|
|||
@Endpoint(org.jclouds.vcloud.endpoints.VCloudApi.class)
|
||||
@Path("/vapp/{vAppId}")
|
||||
@XMLResponseParser(HostingDotComVAppHandler.class)
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
@Override
|
||||
ListenableFuture<? extends HostingDotComVApp> getVApp(@PathParam("vAppId") String appId);
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import javax.inject.Singleton;
|
|||
|
||||
import org.jclouds.Constants;
|
||||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.compute.domain.NodeState;
|
||||
import org.jclouds.compute.domain.Size;
|
||||
import org.jclouds.compute.domain.TemplateBuilder;
|
||||
import org.jclouds.compute.util.ComputeUtils;
|
||||
|
@ -19,6 +20,7 @@ import org.jclouds.domain.Location;
|
|||
import org.jclouds.vcloud.VCloudClient;
|
||||
import org.jclouds.vcloud.compute.VCloudComputeService;
|
||||
import org.jclouds.vcloud.domain.VApp;
|
||||
import org.jclouds.vcloud.domain.VAppStatus;
|
||||
import org.jclouds.vcloud.hostingdotcom.domain.HostingDotComVApp;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
@ -29,17 +31,17 @@ import com.google.common.collect.ImmutableMap;
|
|||
*/
|
||||
@Singleton
|
||||
public class HostingDotComVCloudComputeService extends VCloudComputeService {
|
||||
|
||||
@Inject
|
||||
public HostingDotComVCloudComputeService(VCloudClient client,
|
||||
Provider<TemplateBuilder> templateBuilderProvider,
|
||||
HostingDotComVCloudComputeService(Provider<TemplateBuilder> templateBuilderProvider,
|
||||
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,
|
||||
VCloudClient client, Predicate<String> successTester,
|
||||
@Named("NOT_FOUND") Predicate<VApp> notFoundTester,
|
||||
Map<VAppStatus, NodeState> vAppStatusToNodeState,
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
|
||||
super(client, templateBuilderProvider, images, sizes, locations, utils, successTester,
|
||||
notFoundTester, executor);
|
||||
super(templateBuilderProvider, images, sizes, locations, utils, client, successTester,
|
||||
notFoundTester, vAppStatusToNodeState, executor);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -51,4 +53,5 @@ public class HostingDotComVCloudComputeService extends VCloudComputeService {
|
|||
return ImmutableMap.<String, String> of("id", vAppResponse.getId(), "username", hVApp
|
||||
.getUsername(), "password", hVApp.getPassword());
|
||||
}
|
||||
|
||||
}
|
|
@ -45,6 +45,8 @@ import org.jclouds.rest.annotations.RequestFilters;
|
|||
import org.jclouds.rest.annotations.ResponseParser;
|
||||
import org.jclouds.rest.annotations.XMLResponseParser;
|
||||
import org.jclouds.rest.functions.InetAddressToHostAddress;
|
||||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.vcloud.VCloudAsyncClient;
|
||||
import org.jclouds.vcloud.domain.Catalog;
|
||||
import org.jclouds.vcloud.domain.Task;
|
||||
|
@ -113,6 +115,8 @@ public interface TerremarkVCloudAsyncClient extends VCloudAsyncClient {
|
|||
@Endpoint(org.jclouds.vcloud.endpoints.Catalog.class)
|
||||
@XMLResponseParser(CatalogHandler.class)
|
||||
@Consumes(CATALOG_XML)
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
@Override
|
||||
ListenableFuture<? extends Catalog> getCatalog(String catalogId);
|
||||
|
||||
/**
|
||||
|
@ -123,6 +127,7 @@ public interface TerremarkVCloudAsyncClient extends VCloudAsyncClient {
|
|||
@Path("/vdc/{vDCId}")
|
||||
@XMLResponseParser(TerremarkVDCHandler.class)
|
||||
@Consumes(VDC_XML)
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
@Override
|
||||
ListenableFuture<? extends VDC> getVDC(@PathParam("vDCId") String vDCId);
|
||||
|
||||
|
@ -137,8 +142,8 @@ public interface TerremarkVCloudAsyncClient extends VCloudAsyncClient {
|
|||
@XMLResponseParser(VAppHandler.class)
|
||||
@MapBinder(TerremarkBindInstantiateVAppTemplateParamsToXmlPayload.class)
|
||||
@Override
|
||||
ListenableFuture<? extends VApp> instantiateVAppTemplateInVDC(
|
||||
@PathParam("vDCId") String vDCId, @MapPayloadParam("name") String appName,
|
||||
ListenableFuture<? extends VApp> instantiateVAppTemplateInVDC(@PathParam("vDCId") String vDCId,
|
||||
@MapPayloadParam("name") String appName,
|
||||
@MapPayloadParam("template") @ParamParser(CatalogIdToUri.class) String templateId,
|
||||
InstantiateVAppTemplateOptions... options);
|
||||
|
||||
|
@ -211,6 +216,7 @@ public interface TerremarkVCloudAsyncClient extends VCloudAsyncClient {
|
|||
@Path("/publicIps/{ipId}")
|
||||
@Consumes(APPLICATION_XML)
|
||||
@XMLResponseParser(InternetServicesHandler.class)
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
ListenableFuture<? extends SortedSet<InternetService>> getPublicIp(@PathParam("ipId") int ipId);
|
||||
|
||||
/**
|
||||
|
@ -230,6 +236,7 @@ public interface TerremarkVCloudAsyncClient extends VCloudAsyncClient {
|
|||
@DELETE
|
||||
@Endpoint(org.jclouds.vcloud.endpoints.VCloudApi.class)
|
||||
@Path("/internetServices/{internetServiceId}")
|
||||
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
|
||||
ListenableFuture<Void> deleteInternetService(
|
||||
@PathParam("internetServiceId") int internetServiceId);
|
||||
|
||||
|
@ -254,6 +261,7 @@ public interface TerremarkVCloudAsyncClient extends VCloudAsyncClient {
|
|||
@Path("/internetServices/{internetServiceId}")
|
||||
@Consumes(APPLICATION_XML)
|
||||
@XMLResponseParser(InternetServiceHandler.class)
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
ListenableFuture<? extends InternetService> getInternetService(
|
||||
@PathParam("internetServiceId") int internetServiceId);
|
||||
|
||||
|
@ -292,6 +300,7 @@ public interface TerremarkVCloudAsyncClient extends VCloudAsyncClient {
|
|||
@Path("/nodeServices/{nodeId}")
|
||||
@XMLResponseParser(NodeHandler.class)
|
||||
@Consumes(APPLICATION_XML)
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
ListenableFuture<? extends Node> getNode(@PathParam("nodeId") int nodeId);
|
||||
|
||||
/**
|
||||
|
@ -313,6 +322,7 @@ public interface TerremarkVCloudAsyncClient extends VCloudAsyncClient {
|
|||
@DELETE
|
||||
@Endpoint(org.jclouds.vcloud.endpoints.VCloudApi.class)
|
||||
@Path("/nodeServices/{nodeId}")
|
||||
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
|
||||
ListenableFuture<Void> deleteNode(@PathParam("nodeId") int nodeId);
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,7 +26,6 @@ import java.util.Set;
|
|||
import java.util.SortedSet;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
|
@ -35,15 +34,15 @@ 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.NodeState;
|
||||
import org.jclouds.compute.domain.Size;
|
||||
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;
|
||||
import org.jclouds.vcloud.domain.VAppStatus;
|
||||
import org.jclouds.vcloud.terremark.TerremarkVCloudClient;
|
||||
import org.jclouds.vcloud.terremark.domain.InternetService;
|
||||
import org.jclouds.vcloud.terremark.domain.Node;
|
||||
|
@ -60,21 +59,20 @@ import com.google.common.collect.Sets;
|
|||
*/
|
||||
@Singleton
|
||||
public class TerremarkVCloudComputeService extends VCloudComputeService {
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
private final TerremarkVCloudClient client;
|
||||
|
||||
@Inject
|
||||
public TerremarkVCloudComputeService(TerremarkVCloudClient client,
|
||||
Provider<TemplateBuilder> templateBuilderProvider,
|
||||
TerremarkVCloudComputeService(Provider<TemplateBuilder> templateBuilderProvider,
|
||||
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,
|
||||
TerremarkVCloudClient client, Predicate<String> successTester,
|
||||
@Named("NOT_FOUND") Predicate<VApp> notFoundTester,
|
||||
Map<VAppStatus, NodeState> vAppStatusToNodeState,
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
|
||||
super(client, templateBuilderProvider, images, sizes, locations, utils, successTester,
|
||||
notFoundTester, executor);
|
||||
super(templateBuilderProvider, images, sizes, locations, utils, client, successTester,
|
||||
notFoundTester, vAppStatusToNodeState, executor);
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
|
@ -201,16 +199,13 @@ public class TerremarkVCloudComputeService extends VCloudComputeService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @throws ElementNotFoundException
|
||||
* if no address is configured
|
||||
*/
|
||||
public InetAddress getAnyPrivateAddress(String id) {
|
||||
@Override
|
||||
public Set<InetAddress> getPrivateAddresses(String id) {
|
||||
VApp vApp = client.getVApp(id);
|
||||
return Iterables.getLast(vApp.getNetworkToAddresses().values());
|
||||
return Sets.newHashSet(vApp.getNetworkToAddresses().values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<InetAddress> getPublicAddresses(String id) {
|
||||
VApp vApp = client.getVApp(id);
|
||||
Set<InetAddress> ipAddresses = Sets.newHashSet();
|
||||
|
|
|
@ -42,6 +42,8 @@ import org.jclouds.http.functions.ParseSax;
|
|||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.logging.Logger.LoggerFactory;
|
||||
import org.jclouds.rest.RestClientTest;
|
||||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||
import org.jclouds.util.Jsr330;
|
||||
|
@ -98,7 +100,7 @@ public class TerremarkVCloudAsyncClientTest extends RestClientTest<TerremarkVClo
|
|||
|
||||
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
|
||||
assertSaxResponseParserClassEquals(method, CatalogHandler.class);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(httpMethod);
|
||||
}
|
||||
|
@ -147,7 +149,7 @@ public class TerremarkVCloudAsyncClientTest extends RestClientTest<TerremarkVClo
|
|||
|
||||
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
|
||||
assertSaxResponseParserClassEquals(method, TerremarkVDCHandler.class);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(httpMethod);
|
||||
}
|
||||
|
@ -271,7 +273,7 @@ public class TerremarkVCloudAsyncClientTest extends RestClientTest<TerremarkVClo
|
|||
|
||||
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
|
||||
assertSaxResponseParserClassEquals(method, InternetServiceHandler.class);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(httpMethod);
|
||||
}
|
||||
|
@ -289,7 +291,7 @@ public class TerremarkVCloudAsyncClientTest extends RestClientTest<TerremarkVClo
|
|||
|
||||
assertResponseParserClassEquals(method, httpMethod, CloseContentAndReturn.class);
|
||||
assertSaxResponseParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnVoidOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(httpMethod);
|
||||
}
|
||||
|
@ -388,7 +390,7 @@ public class TerremarkVCloudAsyncClientTest extends RestClientTest<TerremarkVClo
|
|||
|
||||
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
|
||||
assertSaxResponseParserClassEquals(method, NodeHandler.class);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(httpMethod);
|
||||
}
|
||||
|
@ -461,7 +463,7 @@ public class TerremarkVCloudAsyncClientTest extends RestClientTest<TerremarkVClo
|
|||
|
||||
assertResponseParserClassEquals(method, httpMethod, CloseContentAndReturn.class);
|
||||
assertSaxResponseParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnVoidOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(httpMethod);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue