normalized usage of null across compute apis, removed loop of recreating nodes, extracted BaseComputeService class

This commit is contained in:
Adrian Cole 2010-02-08 01:32:53 -08:00
parent 1a5016a4f8
commit 52e40c4651
48 changed files with 996 additions and 1121 deletions

View File

@ -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);

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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> {
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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 + "]";
}
/**

View File

@ -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();
}
}

View File

@ -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 + "]";
}
}

View File

@ -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()));
}

View File

@ -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;
}
}

View File

@ -25,17 +25,19 @@ 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) {
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));
}

View File

@ -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;
}
return Boolean.class.cast(propagateOrNull(from));
} else {
return !rto404.apply(from);
}
}
}

View File

@ -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));
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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

View File

@ -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 {
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;
} catch (ResourceNotFoundException e) {
return false;
}
}
private Server refresh(Server server) {

View File

@ -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 {
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;
} catch (ResourceNotFoundException e) {
return true;
}
}
private Server refresh(Server server) {

View File

@ -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;
}
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -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;
}

View File

@ -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());
}
}

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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;
@ -91,6 +94,7 @@ public interface VCloudAsyncClient {
@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);
@ -104,6 +108,7 @@ public interface VCloudAsyncClient {
@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);
@ -112,20 +117,25 @@ public interface VCloudAsyncClient {
@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

View File

@ -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)));
}
}

View File

@ -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();

View File

@ -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);
}

View File

@ -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);

View File

@ -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());
}
}

View File

@ -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);
/**

View File

@ -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();

View File

@ -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);
}