From be7cf42f044b44756be243959c046a69c72313ee Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Mon, 14 Nov 2011 19:23:41 +0200 Subject: [PATCH] added cloudstack support to launch servers in a network with ip forwarding --- .../CloudStackPropertiesBuilder.java | 2 + ...CloudStackComputeServiceContextModule.java | 64 ++++++++++ .../VirtualMachineToNodeMetadata.java | 21 +++- .../options/CloudStackTemplateOptions.java | 38 ++++++ .../CloudStackComputeServiceAdapter.java | 83 +++++++++---- .../domain/AsyncCreateResponse.java | 30 +++++ .../cloudstack/features/AccountClient.java | 2 +- .../cloudstack/features/NATAsyncClient.java | 26 +++- .../cloudstack/features/NATClient.java | 22 +++- .../features/TemplateAsyncClient.java | 28 +++-- .../StaticNATVirtualMachineInNetwork.java | 92 ++++++++++++++ .../handlers/CloudStackErrorHandler.java | 7 +- .../options/DeployVirtualMachineOptions.java | 20 ++++ .../cloudstack/suppliers/GetCurrentUser.java | 69 +++++++++++ .../suppliers/NetworksForCurrentUser.java | 66 ++++++++++ ...oudStackComputeServiceAdapterLiveTest.java | 84 +++++++++---- .../CloudStackComputeServiceLiveTest.java | 7 +- .../VirtualMachineToNodeMetadataTest.java | 71 ++++++++++- .../CloudStackTemplateOptionsTest.java | 32 +++++ .../BaseCloudStackClientLiveTest.java | 39 +++++- .../features/FirewallClientLiveTest.java | 4 +- .../features/LoadBalancerClientLiveTest.java | 4 +- .../features/NATAsyncClientTest.java | 1 - .../features/NATClientLiveTest.java | 86 ------------- .../features/SecurityGroupClientLiveTest.java | 6 +- .../VirtualMachineClientLiveTest.java | 72 ++++------- ...ticNATVirtualMachineInNetworkLiveTest.java | 113 ++++++++++++++++++ .../handlers/CloudStackErrorHandlerTest.java | 11 ++ 28 files changed, 899 insertions(+), 201 deletions(-) create mode 100644 sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/functions/StaticNATVirtualMachineInNetwork.java create mode 100644 sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/suppliers/GetCurrentUser.java create mode 100644 sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/suppliers/NetworksForCurrentUser.java create mode 100644 sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/functions/StaticNATVirtualMachineInNetworkLiveTest.java diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackPropertiesBuilder.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackPropertiesBuilder.java index 319d92d99f..bebc4f1987 100644 --- a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackPropertiesBuilder.java +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackPropertiesBuilder.java @@ -34,6 +34,8 @@ public class CloudStackPropertiesBuilder extends PropertiesBuilder { protected Properties defaultProperties() { Properties properties = super.defaultProperties(); properties.setProperty(PROPERTY_API_VERSION, "2.2"); + properties.setProperty("jclouds.ssh.max-retries", "7"); + properties.setProperty("jclouds.ssh.retry-auth", "true"); return properties; } diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/config/CloudStackComputeServiceContextModule.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/config/CloudStackComputeServiceContextModule.java index 6e1eef7e9f..77682a28f8 100644 --- a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/config/CloudStackComputeServiceContextModule.java +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/config/CloudStackComputeServiceContextModule.java @@ -18,11 +18,13 @@ */ package org.jclouds.cloudstack.compute.config; +import static com.google.common.base.Preconditions.checkNotNull; import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; import java.util.Map; import java.util.concurrent.TimeUnit; +import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; @@ -35,13 +37,19 @@ import org.jclouds.cloudstack.compute.functions.VirtualMachineToNodeMetadata; import org.jclouds.cloudstack.compute.functions.ZoneToLocation; import org.jclouds.cloudstack.compute.options.CloudStackTemplateOptions; import org.jclouds.cloudstack.compute.strategy.CloudStackComputeServiceAdapter; +import org.jclouds.cloudstack.domain.IPForwardingRule; +import org.jclouds.cloudstack.domain.Network; import org.jclouds.cloudstack.domain.OSType; import org.jclouds.cloudstack.domain.ServiceOffering; import org.jclouds.cloudstack.domain.Template; +import org.jclouds.cloudstack.domain.User; import org.jclouds.cloudstack.domain.VirtualMachine; import org.jclouds.cloudstack.domain.Zone; import org.jclouds.cloudstack.features.GuestOSClient; +import org.jclouds.cloudstack.functions.StaticNATVirtualMachineInNetwork; import org.jclouds.cloudstack.predicates.JobComplete; +import org.jclouds.cloudstack.suppliers.GetCurrentUser; +import org.jclouds.cloudstack.suppliers.NetworksForCurrentUser; import org.jclouds.collect.Memoized; import org.jclouds.compute.ComputeServiceAdapter; import org.jclouds.compute.config.ComputeServiceAdapterContextModule; @@ -51,14 +59,19 @@ import org.jclouds.compute.options.TemplateOptions; import org.jclouds.domain.Location; import org.jclouds.location.suppliers.OnlyLocationOrFirstZone; import org.jclouds.predicates.RetryablePredicate; +import org.jclouds.rest.ResourceNotFoundException; import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Supplier; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; import com.google.common.collect.Maps; import com.google.inject.Provides; import com.google.inject.TypeLiteral; +import com.google.inject.assistedinject.FactoryModuleBuilder; /** * @@ -90,6 +103,9 @@ public class CloudStackComputeServiceContextModule bind(TemplateOptions.class).to(CloudStackTemplateOptions.class); bind(new TypeLiteral>() { }).to(TemplateToOperatingSystem.class); + install(new FactoryModuleBuilder().build(StaticNATVirtualMachineInNetwork.Factory.class)); + bind(new TypeLiteral>() { + }).to(GetIPForwardingRuleByVirtualMachine.class); } @Provides @@ -128,10 +144,58 @@ public class CloudStackComputeServiceContextModule }); } + @Provides + @Singleton + @Memoized + public Supplier> listNetworks(@Named(PROPERTY_SESSION_INTERVAL) long seconds, + final NetworksForCurrentUser networksForCurrentUser) { + return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier>(authException, + seconds, networksForCurrentUser); + } + + @Provides + @Singleton + @Memoized + public Supplier getCurrentUser(@Named(PROPERTY_SESSION_INTERVAL) long seconds, + final GetCurrentUser getCurrentUser) { + return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier(authException, seconds, + getCurrentUser); + } + @Provides @Singleton protected Predicate jobComplete(JobComplete jobComplete) { // TODO: parameterize return new RetryablePredicate(jobComplete, 1200, 1, 5, TimeUnit.SECONDS); } + + @Provides + @Singleton + protected Cache getIPForwardingRuleByVirtualMachine( + CacheLoader getIPForwardingRule) { + return CacheBuilder.newBuilder().build(getIPForwardingRule); + } + + @Singleton + public static class GetIPForwardingRuleByVirtualMachine extends CacheLoader { + private final CloudStackClient client; + + @Inject + public GetIPForwardingRuleByVirtualMachine(CloudStackClient client) { + this.client = checkNotNull(client, "client"); + } + + /** + * @throws ResourceNotFoundException + * when there is no ip forwarding rule available for the VM + */ + @Override + public IPForwardingRule load(Long input) { + IPForwardingRule rule = client.getNATClient().getIPForwardingRuleForVirtualMachine(input); + if (rule == null) + throw new ResourceNotFoundException("no ip forwarding rule for: " + input); + return rule; + } + } + } \ No newline at end of file diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadata.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadata.java index 7ed71f5719..b4376272bd 100644 --- a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadata.java +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadata.java @@ -27,6 +27,7 @@ import java.util.Set; import javax.inject.Inject; import javax.inject.Singleton; +import org.jclouds.cloudstack.domain.IPForwardingRule; import org.jclouds.cloudstack.domain.VirtualMachine; import org.jclouds.collect.FindResourceInSet; import org.jclouds.collect.Memoized; @@ -37,12 +38,17 @@ import org.jclouds.compute.domain.NodeMetadataBuilder; import org.jclouds.compute.domain.NodeState; import org.jclouds.domain.Credentials; import org.jclouds.domain.Location; +import org.jclouds.rest.ResourceNotFoundException; import org.jclouds.util.InetAddresses2; +import org.jclouds.util.Throwables2; import com.google.common.base.Function; import com.google.common.base.Supplier; +import com.google.common.base.Throwables; +import com.google.common.cache.Cache; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.google.common.util.concurrent.UncheckedExecutionException; /** * @author Adrian Cole @@ -66,16 +72,20 @@ public class VirtualMachineToNodeMetadata implements Function getIPForwardingRuleByVirtualMachine; @Inject VirtualMachineToNodeMetadata(Map credentialStore, FindLocationForVirtualMachine findLocationForVirtualMachine, FindHardwareForVirtualMachine findHardwareForVirtualMachine, - FindImageForVirtualMachine findImageForVirtualMachine) { + FindImageForVirtualMachine findImageForVirtualMachine, + Cache getIPForwardingRuleByVirtualMachine) { this.credentialStore = checkNotNull(credentialStore, "credentialStore"); this.findLocationForVirtualMachine = checkNotNull(findLocationForVirtualMachine, "findLocationForVirtualMachine"); this.findHardwareForVirtualMachine = checkNotNull(findHardwareForVirtualMachine, "findHardwareForVirtualMachine"); this.findImageForVirtualMachine = checkNotNull(findImageForVirtualMachine, "findImageForVirtualMachine"); + this.getIPForwardingRuleByVirtualMachine = checkNotNull(getIPForwardingRuleByVirtualMachine, + "getIPForwardingRuleByVirtualMachine"); } @Override @@ -108,6 +118,15 @@ public class VirtualMachineToNodeMetadata implements Function of(rule.getIPAddress())); + } catch (UncheckedExecutionException e) { + if (Throwables2.getFirstThrowableOfType(e, ResourceNotFoundException.class) == null) { + Throwables.propagateIfPossible(e.getCause()); + throw e; + } + } builder.credentials(credentialStore.get("node#" + from.getId())); return builder.build(); } diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/options/CloudStackTemplateOptions.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/options/CloudStackTemplateOptions.java index 0d3869ddce..3e0fa701aa 100644 --- a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/options/CloudStackTemplateOptions.java +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/options/CloudStackTemplateOptions.java @@ -55,6 +55,7 @@ import com.google.common.collect.Sets; public class CloudStackTemplateOptions extends TemplateOptions implements Cloneable { protected Set securityGroupIds = Sets. newLinkedHashSet(); + protected Set networkIds = Sets. newLinkedHashSet(); protected String keyPair; @Override @@ -70,6 +71,7 @@ public class CloudStackTemplateOptions extends TemplateOptions implements Clonea if (to instanceof CloudStackTemplateOptions) { CloudStackTemplateOptions eTo = CloudStackTemplateOptions.class.cast(to); eTo.securityGroupIds(this.securityGroupIds); + eTo.keyPair(this.keyPair); } } @@ -93,6 +95,26 @@ public class CloudStackTemplateOptions extends TemplateOptions implements Clonea return securityGroupIds; } + /** + * @see DeployVirtualMachineOptions#networkId + */ + public CloudStackTemplateOptions networkId(long networkId) { + this.networkIds.add(networkId); + return this; + } + + /** + * @see DeployVirtualMachineOptions#networkIds + */ + public CloudStackTemplateOptions networkIds(Iterable networkIds) { + Iterables.addAll(this.networkIds, checkNotNull(networkIds, "networkIds was null")); + return this; + } + + public Set getNetworkIds() { + return networkIds; + } + /** * @see DeployVirtualMachineOptions#keyPair(String) */ @@ -125,6 +147,22 @@ public class CloudStackTemplateOptions extends TemplateOptions implements Clonea return options.securityGroupIds(securityGroupIds); } + /** + * @see CloudStackTemplateOptions#networkId + */ + public static CloudStackTemplateOptions networkId(long id) { + CloudStackTemplateOptions options = new CloudStackTemplateOptions(); + return options.networkId(id); + } + + /** + * @see CloudStackTemplateOptions#networkIds + */ + public static CloudStackTemplateOptions networkIds(Iterable networkIds) { + CloudStackTemplateOptions options = new CloudStackTemplateOptions(); + return options.networkIds(networkIds); + } + /** * @see CloudStackTemplateOptions#keyPair */ diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/strategy/CloudStackComputeServiceAdapter.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/strategy/CloudStackComputeServiceAdapter.java index cc6c6ef39f..00643c45b3 100644 --- a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/strategy/CloudStackComputeServiceAdapter.java +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/strategy/CloudStackComputeServiceAdapter.java @@ -20,7 +20,9 @@ package org.jclouds.cloudstack.compute.strategy; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Throwables.propagate; import static com.google.common.collect.Iterables.filter; +import static com.google.common.collect.Iterables.getOnlyElement; import java.util.Map; import java.util.concurrent.ExecutionException; @@ -30,17 +32,21 @@ import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; -import com.google.common.base.Predicates; import org.jclouds.cloudstack.CloudStackClient; import org.jclouds.cloudstack.compute.options.CloudStackTemplateOptions; import org.jclouds.cloudstack.domain.AsyncCreateResponse; import org.jclouds.cloudstack.domain.AsyncJob; +import org.jclouds.cloudstack.domain.Network; +import org.jclouds.cloudstack.domain.PublicIPAddress; import org.jclouds.cloudstack.domain.ServiceOffering; import org.jclouds.cloudstack.domain.Template; import org.jclouds.cloudstack.domain.VirtualMachine; import org.jclouds.cloudstack.domain.Zone; +import org.jclouds.cloudstack.functions.StaticNATVirtualMachineInNetwork; +import org.jclouds.cloudstack.functions.StaticNATVirtualMachineInNetwork.Factory; import org.jclouds.cloudstack.options.DeployVirtualMachineOptions; import org.jclouds.cloudstack.predicates.TemplatePredicates; +import org.jclouds.collect.Memoized; import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeServiceAdapter; import org.jclouds.compute.reference.ComputeServiceConstants; @@ -48,7 +54,7 @@ import org.jclouds.domain.Credentials; import org.jclouds.logging.Logger; import com.google.common.base.Predicate; -import com.google.common.base.Throwables; +import com.google.common.base.Supplier; /** * defines the connection between the {@link CloudStackClient} implementation @@ -65,63 +71,96 @@ public class CloudStackComputeServiceAdapter implements private final CloudStackClient client; private final Predicate jobComplete; + private final Supplier> networkSupplier; + private final Factory staticNATVMInNetwork; + private final Map credentialStore; @Inject - public CloudStackComputeServiceAdapter(CloudStackClient client, Predicate jobComplete) { + public CloudStackComputeServiceAdapter(CloudStackClient client, Predicate jobComplete, + @Memoized Supplier> networkSupplier, + StaticNATVirtualMachineInNetwork.Factory staticNATVMInNetwork, Map credentialStore) { this.client = checkNotNull(client, "client"); - this.jobComplete=checkNotNull(jobComplete, "jobComplete"); + this.jobComplete = checkNotNull(jobComplete, "jobComplete"); + this.networkSupplier = checkNotNull(networkSupplier, "networkSupplier"); + this.staticNATVMInNetwork = checkNotNull(staticNATVMInNetwork, "staticNATVMInNetwork"); + this.credentialStore = checkNotNull(credentialStore, "credentialStore"); } @Override - public VirtualMachine createNodeWithGroupEncodedIntoNameThenStoreCredentials(String group, String name, - org.jclouds.compute.domain.Template template, Map credentialStore) { + public NodeAndInitialCredentials createNodeWithGroupEncodedIntoName(String group, String name, + org.jclouds.compute.domain.Template template) { checkNotNull(template, "template was null"); checkNotNull(template.getOptions(), "template options was null"); checkArgument(template.getOptions().getClass().isAssignableFrom(CloudStackTemplateOptions.class), "options class %s should have been assignable from CloudStackTemplateOptions", template.getOptions() .getClass()); + Map networks = networkSupplier.get(); + + final long zoneId = Long.parseLong(template.getLocation().getId()); + CloudStackTemplateOptions templateOptions = template.getOptions().as(CloudStackTemplateOptions.class); DeployVirtualMachineOptions options = new DeployVirtualMachineOptions(); - if (templateOptions.getSecurityGroupIds().size() > 0) + if (templateOptions.getSecurityGroupIds().size() > 0) { options.securityGroupIds(templateOptions.getSecurityGroupIds()); + } else if (templateOptions.getNetworkIds().size() > 0) { + options.networkIds(templateOptions.getNetworkIds()); + } else if (networks.size() > 0) { + try { + options.networkId(getOnlyElement(filter(networks.values(), new Predicate() { + + @Override + public boolean apply(Network arg0) { + return arg0.getZoneId() == zoneId; + } + + })).getId()); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("please choose a specific network in zone " + zoneId + ": " + networks); + } + } else { + throw new IllegalArgumentException("please setup a network or security group for zone: " + zoneId); + } if (templateOptions.getKeyPair() != null) { options.keyPair(templateOptions.getKeyPair()); if (templateOptions.getRunScript() != null) { - checkArgument( - credentialStore.containsKey("keypair#" + templateOptions.getKeyPair()), - "no private key configured for: %s; please use options.overrideLoginCredentialWith(rsa_private_text)", - templateOptions.getKeyPair()); + checkArgument( + credentialStore.containsKey("keypair#" + templateOptions.getKeyPair()), + "no private key configured for: %s; please use options.overrideLoginCredentialWith(rsa_private_text)", + templateOptions.getKeyPair()); } } - long zoneId = Long.parseLong(template.getLocation().getId()); long templateId = Long.parseLong(template.getImage().getId()); long serviceOfferingId = Long.parseLong(template.getHardware().getId()); - System.out.printf("serviceOfferingId %d, templateId %d, zoneId %d, options %s%n", serviceOfferingId, templateId, + logger.info("serviceOfferingId %d, templateId %d, zoneId %d, options %s%n", serviceOfferingId, templateId, zoneId, options); AsyncCreateResponse job = client.getVirtualMachineClient().deployVirtualMachineInZone(zoneId, serviceOfferingId, templateId, options); - assert jobComplete.apply(job.getJobId()); + boolean completed = jobComplete.apply(job.getJobId()); AsyncJob jobWithResult = client.getAsyncJobClient(). getAsyncJob(job.getJobId()); + assert completed : jobWithResult; if (jobWithResult.getError() != null) - Throwables.propagate(new ExecutionException(String.format("job %s failed with exception %s", job.getId(), - jobWithResult.getError().toString())) { + propagate(new ExecutionException(String.format("job %s failed with exception %s", job.getId(), jobWithResult + .getError().toString())) { private static final long serialVersionUID = 4371112085613620239L; }); VirtualMachine vm = jobWithResult.getResult(); + Credentials credentials = null; if (vm.isPasswordEnabled()) { assert vm.getPassword() != null : vm; - Credentials credentials = new Credentials("root", vm.getPassword()); - credentialStore.put("node#" + vm.getId(), credentials); + credentials = new Credentials(null, vm.getPassword()); } else { - // assert templateOptions.getKeyPair() != null : vm; - Credentials credentials = credentialStore.get("keypair#" + templateOptions.getKeyPair()); - credentialStore.put("node#" + vm.getId(), credentials); + credentials = credentialStore.get("keypair#" + templateOptions.getKeyPair()); } - return vm; + // TODO: possibly not all network ids, do we want to do this + for (long networkId : options.getNetworkIds()) { + // TODO: log this + PublicIPAddress ip = staticNATVMInNetwork.create(networks.get(networkId)).apply(vm); + } + return new NodeAndInitialCredentials(vm, vm.getId() + "", credentials); } @Override diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/AsyncCreateResponse.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/AsyncCreateResponse.java index f9f5736df0..d45cc620a4 100644 --- a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/AsyncCreateResponse.java +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/AsyncCreateResponse.java @@ -56,4 +56,34 @@ public class AsyncCreateResponse { return jobId; } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (int) (id ^ (id >>> 32)); + result = prime * result + (int) (jobId ^ (jobId >>> 32)); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + AsyncCreateResponse other = (AsyncCreateResponse) obj; + if (id != other.id) + return false; + if (jobId != other.jobId) + return false; + return true; + } + + @Override + public String toString() { + return "[id=" + id + ", jobId=" + jobId + "]"; + } + } diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/AccountClient.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/AccountClient.java index 95320a366c..dbaf6f6d3a 100644 --- a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/AccountClient.java +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/AccountClient.java @@ -32,7 +32,7 @@ import org.jclouds.concurrent.Timeout; * @see * @author Adrian Cole */ -@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS) +@Timeout(duration = 120, timeUnit = TimeUnit.SECONDS) public interface AccountClient { /** * Lists Accounts diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/NATAsyncClient.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/NATAsyncClient.java index c523274e30..69a59334ac 100644 --- a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/NATAsyncClient.java +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/NATAsyncClient.java @@ -46,7 +46,9 @@ import com.google.common.util.concurrent.ListenableFuture; *

* * @see NATClient - * @see + * @see * @author Adrian Cole */ @RequestFilters(QuerySigner.class) @@ -74,6 +76,28 @@ public interface NATAsyncClient { @ExceptionParser(ReturnNullOnNotFoundOr404.class) ListenableFuture getIPForwardingRule(@QueryParam("id") long id); + /** + * @see NATClient#getIPForwardingRuleForIPAddress + */ + @GET + @QueryParams(keys = "command", values = "listIpForwardingRules") + @SelectJson("ipforwardingrule") + @OnlyElement + @Consumes(MediaType.APPLICATION_JSON) + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + ListenableFuture getIPForwardingRuleForIPAddress(@QueryParam("ipaddressid") long id); + + /** + * @see NATClient#getIPForwardingRuleForVirtualMachine + */ + @GET + @QueryParams(keys = "command", values = "listIpForwardingRules") + @SelectJson("ipforwardingrule") + @OnlyElement + @Consumes(MediaType.APPLICATION_JSON) + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + ListenableFuture getIPForwardingRuleForVirtualMachine(@QueryParam("virtualmachineid") long id); + /** * @see NATClient#createIPForwardingRule */ diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/NATClient.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/NATClient.java index a1112e707a..b5ebe00e2b 100644 --- a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/NATClient.java +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/NATClient.java @@ -32,7 +32,9 @@ import org.jclouds.concurrent.Timeout; *

* * @see IPForwardingRuleAsyncClient - * @see + * @see * @author Adrian Cole */ @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS) @@ -56,6 +58,24 @@ public interface NATClient { */ IPForwardingRule getIPForwardingRule(long id); + /** + * get a specific IPForwardingRule by ipaddress id + * + * @param id + * IPAddress of rule to get + * @return IPForwardingRule or null if not found + */ + IPForwardingRule getIPForwardingRuleForIPAddress(long id); + + /** + * get a specific IPForwardingRule by virtual machine id + * + * @param id + * virtual machine of rule to get + * @return IPForwardingRule or null if not found + */ + IPForwardingRule getIPForwardingRuleForVirtualMachine(long id); + /** * Creates an ip forwarding rule * diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/TemplateAsyncClient.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/TemplateAsyncClient.java index 9c3fb6599d..b29e274f3c 100644 --- a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/TemplateAsyncClient.java +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/TemplateAsyncClient.java @@ -50,16 +50,18 @@ import org.jclouds.rest.annotations.SkipEncoding; import org.jclouds.rest.annotations.Unwrap; import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404; import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; +import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404; import com.google.common.util.concurrent.ListenableFuture; -import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404; /** * Provides asynchronous access to cloudstack via their REST API. *

* * @see TemplateClient - * @see + * @see * @author Adrian Cole */ @RequestFilters(QuerySigner.class) @@ -74,7 +76,9 @@ public interface TemplateAsyncClient { @QueryParams(keys = "command", values = "createTemplate") @Unwrap @Consumes(MediaType.APPLICATION_JSON) - ListenableFuture createTemplate(@BinderParam(BindTemplateMetadataToQueryParams.class) TemplateMetadata templateMetadata, CreateTemplateOptions... options); + ListenableFuture createTemplate( + @BinderParam(BindTemplateMetadataToQueryParams.class) TemplateMetadata templateMetadata, + CreateTemplateOptions... options); /** * @see TemplateClient#registerTemplate @@ -83,7 +87,10 @@ public interface TemplateAsyncClient { @QueryParams(keys = "command", values = "registerTemplate") @SelectJson("template") @Consumes(MediaType.APPLICATION_JSON) - ListenableFuture