From e8038f5d48327bc147ac87f02b0d40f1bcba6e9e Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sun, 27 Feb 2011 21:01:07 -0800 Subject: [PATCH] added function to obtain a new ip or reuse --- sandbox-apis/cloudstack/pom.xml | 16 +- .../domain/AsyncCreateResponse.java | 5 + .../features/AddressAsyncClient.java | 4 +- ...tFoundOr404OrUnableToFindAccountOwner.java | 57 +++++++ .../ReuseOrAssociateNewPublicIPAddress.java | 108 ++++++++++++ .../cloudstack/predicates/JobComplete.java | 12 +- .../predicates/NetworkPredicates.java | 154 ++++++++++++++++++ .../predicates/PublicIPAddressPredicates.java | 91 +++++++++++ .../features/AddressAsyncClientTest.java | 4 +- .../features/AddressClientLiveTest.java | 57 +------ .../features/AsyncJobClientLiveTest.java | 5 +- .../BaseCloudStackClientLiveTest.java | 23 ++- .../features/FirewallClientLiveTest.java | 46 +++--- .../features/LoadBalancerClientLiveTest.java | 51 ++++-- .../features/NATClientLiveTest.java | 40 +++-- .../VirtualMachineClientLiveTest.java | 11 +- ...euseOrAssociateNewPublicIPAddressTest.java | 154 ++++++++++++++++++ .../predicates/NetworkPredicatesTest.java | 88 ++++++++++ .../PublicIPAddressPredicatesTest.java | 71 ++++++++ .../cloudstack/src/test/resources/log4j.xml | 2 +- 20 files changed, 885 insertions(+), 114 deletions(-) create mode 100644 sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/functions/ReturnVoidOnNotFoundOr404OrUnableToFindAccountOwner.java create mode 100644 sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/functions/ReuseOrAssociateNewPublicIPAddress.java create mode 100644 sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/predicates/NetworkPredicates.java create mode 100644 sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/predicates/PublicIPAddressPredicates.java create mode 100644 sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/functions/ReuseOrAssociateNewPublicIPAddressTest.java create mode 100644 sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/predicates/NetworkPredicatesTest.java create mode 100644 sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/predicates/PublicIPAddressPredicatesTest.java diff --git a/sandbox-apis/cloudstack/pom.xml b/sandbox-apis/cloudstack/pom.xml index 80382c8245..6054bd25ae 100644 --- a/sandbox-apis/cloudstack/pom.xml +++ b/sandbox-apis/cloudstack/pom.xml @@ -51,7 +51,7 @@ http://localhost:8080/client/api - 2.2 + 2.2.0 FIXME_apiKey FIXME_secretKey @@ -68,6 +68,18 @@ test-jar test + + org.jclouds + jclouds-compute + ${project.version} + + + org.jclouds + jclouds-compute + ${project.version} + test-jar + test + org.jclouds.driver jclouds-jsch @@ -108,6 +120,8 @@ test + + 2 test.cloudstack.endpoint 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 b89b447204..5c310112ce 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 @@ -38,6 +38,11 @@ public class AsyncCreateResponse { } + public AsyncCreateResponse(long id, long jobId) { + this.id = id; + this.jobId = jobId; + } + /** * @return id of the resource being created */ diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/AddressAsyncClient.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/AddressAsyncClient.java index 2df5da9e99..6bf2cba660 100644 --- a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/AddressAsyncClient.java +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/AddressAsyncClient.java @@ -29,6 +29,7 @@ import javax.ws.rs.core.MediaType; import org.jclouds.cloudstack.domain.AsyncCreateResponse; import org.jclouds.cloudstack.domain.PublicIPAddress; import org.jclouds.cloudstack.filters.QuerySigner; +import org.jclouds.cloudstack.functions.ReturnVoidOnNotFoundOr404OrUnableToFindAccountOwner; import org.jclouds.cloudstack.options.AssociateIPAddressOptions; import org.jclouds.cloudstack.options.ListPublicIPAddressesOptions; import org.jclouds.rest.annotations.ExceptionParser; @@ -37,7 +38,6 @@ import org.jclouds.rest.annotations.RequestFilters; 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; @@ -88,7 +88,7 @@ public interface AddressAsyncClient { */ @GET @QueryParams(keys = "command", values = "disassociateIpAddress") - @ExceptionParser(ReturnVoidOnNotFoundOr404.class) + @ExceptionParser(ReturnVoidOnNotFoundOr404OrUnableToFindAccountOwner.class) ListenableFuture disassociateIPAddress(@QueryParam("id") long id); } diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/functions/ReturnVoidOnNotFoundOr404OrUnableToFindAccountOwner.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/functions/ReturnVoidOnNotFoundOr404OrUnableToFindAccountOwner.java new file mode 100644 index 0000000000..e86d119065 --- /dev/null +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/functions/ReturnVoidOnNotFoundOr404OrUnableToFindAccountOwner.java @@ -0,0 +1,57 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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.cloudstack.functions; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404; +import org.jclouds.util.Throwables2; + +import com.google.common.base.Function; + +/** + * CloudStack is currently sending 431 errors with the text "Unable to find account owner for ip ". + * In this case, we have to ignore as there's no means for us to avoid the problem, or action to + * take. + * + * @author Adrian Cole + */ +@Singleton +public class ReturnVoidOnNotFoundOr404OrUnableToFindAccountOwner implements Function { + + private final ReturnVoidOnNotFoundOr404 rto404; + + @Inject + private ReturnVoidOnNotFoundOr404OrUnableToFindAccountOwner(ReturnVoidOnNotFoundOr404 rto404) { + this.rto404 = checkNotNull(rto404, "rto404"); + } + + public Void apply(Exception from) { + IllegalStateException e = Throwables2.getFirstThrowableOfType(from, IllegalStateException.class); + if (e != null && e.getMessage().indexOf("Unable to find account owner for") != -1) { + return null; + } else { + return rto404.apply(from); + } + } +} \ No newline at end of file diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/functions/ReuseOrAssociateNewPublicIPAddress.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/functions/ReuseOrAssociateNewPublicIPAddress.java new file mode 100644 index 0000000000..e194032dc3 --- /dev/null +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/functions/ReuseOrAssociateNewPublicIPAddress.java @@ -0,0 +1,108 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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.cloudstack.functions; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Predicates.and; +import static com.google.common.collect.Iterables.find; +import static org.jclouds.cloudstack.options.AssociateIPAddressOptions.Builder.networkId; +import static org.jclouds.cloudstack.options.ListPublicIPAddressesOptions.Builder.allocatedOnly; +import static org.jclouds.cloudstack.predicates.PublicIPAddressPredicates.associatedWithNetwork; +import static org.jclouds.cloudstack.predicates.PublicIPAddressPredicates.available; +import static org.jclouds.compute.reference.ComputeServiceConstants.COMPUTE_LOGGER; + +import java.util.NoSuchElementException; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.cloudstack.CloudStackClient; +import org.jclouds.cloudstack.domain.AsyncCreateResponse; +import org.jclouds.cloudstack.domain.Network; +import org.jclouds.cloudstack.domain.PublicIPAddress; +import org.jclouds.cloudstack.features.AddressClient; +import org.jclouds.logging.Logger; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; + +/** + * + * @author Adrian Cole + */ +@Singleton +public class ReuseOrAssociateNewPublicIPAddress implements Function { + private final CloudStackClient client; + private final Predicate jobComplete; + @Resource + @Named(COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + @Inject + public + ReuseOrAssociateNewPublicIPAddress(CloudStackClient client, Predicate jobComplete) { + this.client = checkNotNull(client, "client"); + this.jobComplete = checkNotNull(jobComplete, "jobComplete"); + } + + /** + * Finds existing addresses who are ready for use and not assigned to a machine. + * + * @param networkId + * network id to search + * @param client + * address client + * @return address to use + * @throws NoSuchElementException + * if there's no existing ip address that is free for use + */ + public static PublicIPAddress findAvailableAndAssociatedWithNetwork(long networkId, AddressClient client) { + return find(client.listPublicIPAddresses(allocatedOnly(true).networkId(networkId)), and( + associatedWithNetwork(networkId), available())); + } + + public static PublicIPAddress associateIPAddressInNetwork(Network network, CloudStackClient client, + Predicate jobComplete) { + AsyncCreateResponse job = client.getAddressClient().associateIPAddress(network.getZoneId(), + networkId(network.getId())); + checkState(jobComplete.apply(job.getJobId()), "job %d failed to complete", job.getJobId()); + PublicIPAddress ip = client.getAsyncJobClient(). getAsyncJob(job.getJobId()).getResult(); + assert ip.getZoneId() == network.getZoneId(); + return ip; + } + + @Override + public PublicIPAddress apply(Network input) { + try { + logger.debug(">> looking for existing address in network %d", input.getId()); + PublicIPAddress returnVal = findAvailableAndAssociatedWithNetwork(input.getId(), client.getAddressClient()); + logger.debug("<< address(%d)", returnVal.getId()); + return returnVal; + } catch (NoSuchElementException e) { + logger.debug(">> associating new address in network %d", input.getId()); + PublicIPAddress returnVal = associateIPAddressInNetwork(input, client, jobComplete); + logger.debug("<< address(%d)", returnVal.getId()); + return returnVal; + } + } +} diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/predicates/JobComplete.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/predicates/JobComplete.java index e5ca531dbd..5d05d32440 100644 --- a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/predicates/JobComplete.java +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/predicates/JobComplete.java @@ -21,6 +21,8 @@ package org.jclouds.cloudstack.predicates; import static com.google.common.base.Preconditions.checkNotNull; +import java.util.concurrent.ExecutionException; + import javax.annotation.Resource; import javax.inject.Singleton; @@ -29,6 +31,7 @@ import org.jclouds.cloudstack.domain.AsyncJob; import org.jclouds.logging.Logger; import com.google.common.base.Predicate; +import com.google.common.base.Throwables; import com.google.inject.Inject; /** @@ -52,14 +55,19 @@ public class JobComplete implements Predicate { public boolean apply(Long jobId) { logger.trace("looking for status on job %s", checkNotNull(jobId, "jobId")); - AsyncJob job = refresh(jobId); + AsyncJob job = refresh(jobId); if (job == null) return false; logger.trace("%s: looking for job status %s: currently: %s", job.getId(), 1, job.getStatus()); + if (job.getError() != null) + Throwables.propagate(new ExecutionException(String.format("job %s failed with exception %s", job.getId(), job + .getError().toString())) { + private static final long serialVersionUID = 4371112085613620239L; + }); return job.getStatus() > 0; } - private AsyncJob refresh(Long jobId) { + private AsyncJob refresh(Long jobId) { return client.getAsyncJobClient().getAsyncJob(jobId); } } diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/predicates/NetworkPredicates.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/predicates/NetworkPredicates.java new file mode 100644 index 0000000000..2aa5257829 --- /dev/null +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/predicates/NetworkPredicates.java @@ -0,0 +1,154 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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.cloudstack.predicates; + +import static com.google.common.base.Preconditions.checkNotNull; + +import org.jclouds.cloudstack.domain.Network; +import org.jclouds.cloudstack.domain.NetworkService; + +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.collect.Iterables; + +/** + * + * @author Adrian Cole + */ +public class NetworkPredicates { + + public static enum HasFirewallServiceWhichSupportsStaticNAT implements Predicate { + INSTANCE; + + @Override + public boolean apply(Network arg0) { + return Iterables.any(checkNotNull(arg0, "network").getServices(), supportsStaticNAT); + } + + @Override + public String toString() { + return supportsStaticNAT.toString(); + } + } + + public static enum HasFirewallServiceWhichSupportsPortForwarding implements Predicate { + INSTANCE; + + @Override + public boolean apply(Network arg0) { + return Iterables.any(checkNotNull(arg0, "network").getServices(), supportsPortForwarding); + } + + @Override + public String toString() { + return supportsPortForwarding.toString(); + } + } + + public static enum HasLoadBalancerService implements Predicate { + INSTANCE; + + @Override + public boolean apply(Network arg0) { + return Iterables.any(checkNotNull(arg0, "network").getServices(), isLoadBalancerService); + } + + @Override + public String toString() { + return isLoadBalancerService.toString(); + } + } + + public static class NetworkServiceNamed implements Predicate { + private final String name; + + public NetworkServiceNamed(String name) { + this.name = checkNotNull(name, "name"); + } + + @Override + public boolean apply(NetworkService input) { + return name.equals(checkNotNull(input, "networkService").getName()); + } + + @Override + public String toString() { + return "networkServiceNamed(" + name + ")"; + } + } + + public static class CapabilitiesInclude implements Predicate { + private final String capability; + + public CapabilitiesInclude(String capability) { + this.capability = checkNotNull(capability, "capability"); + } + + @Override + public boolean apply(NetworkService input) { + return "true".equals(input.getCapabilities().get(capability)); + } + + @Override + public String toString() { + return "capabilitiesInclude(" + capability + ")"; + } + } + + public static Predicate supportsStaticNAT = Predicates.and(new NetworkServiceNamed("Firewall"), + new CapabilitiesInclude("StaticNat")); + + public static Predicate supportsPortForwarding = Predicates.and(new NetworkServiceNamed("Firewall"), + new CapabilitiesInclude("PortForwarding")); + + public static Predicate isLoadBalancerService = new NetworkServiceNamed("Lb"); + + /** + * + * @return true, if the network supports static NAT. + */ + public static Predicate supportsStaticNAT() { + return HasFirewallServiceWhichSupportsStaticNAT.INSTANCE; + } + + /** + * + * @return true, if the network supports port forwarding. + */ + public static Predicate supportsPortForwarding() { + return HasFirewallServiceWhichSupportsPortForwarding.INSTANCE; + } + + /** + * + * @return true, if the network supports load balancing. + */ + public static Predicate hasLoadBalancerService() { + return HasLoadBalancerService.INSTANCE; + } + + /** + * + * @return always returns true. + */ + public static Predicate any() { + return Predicates.alwaysTrue(); + } +} diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/predicates/PublicIPAddressPredicates.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/predicates/PublicIPAddressPredicates.java new file mode 100644 index 0000000000..a206e1d874 --- /dev/null +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/predicates/PublicIPAddressPredicates.java @@ -0,0 +1,91 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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.cloudstack.predicates; + +import static com.google.common.base.Preconditions.checkNotNull; + +import org.jclouds.cloudstack.domain.PublicIPAddress; + +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; + +/** + * + * @author Adrian Cole + */ +public class PublicIPAddressPredicates { + + public static final class AssociatedWithNetwork implements Predicate { + private final long networkId; + + public AssociatedWithNetwork(long networkId) { + this.networkId = networkId; + } + + @Override + public boolean apply(PublicIPAddress input) { + return checkNotNull(input, "ipaddress").getAssociatedNetworkId() == networkId; + } + + @Override + public String toString() { + return "associatedWithNetwork(" + networkId + ")"; + } + } + + public static enum Available implements Predicate { + INSTANCE; + + @Override + public boolean apply(PublicIPAddress arg0) { + return !checkNotNull(arg0, "ipaddress").isSourceNAT() && !arg0.isStaticNAT() + && arg0.getVirtualMachineId() <= 0 && arg0.getState() == PublicIPAddress.State.ALLOCATED; + } + + @Override + public String toString() { + return "available()"; + } + } + + /** + * + * @return true, if the public ip address is not assigned to a VM or NAT rule + */ + public static Predicate available() { + return Available.INSTANCE; + } + + /** + * + * @return true, if the public ip address is associated with the specified network + */ + public static Predicate associatedWithNetwork(final long networkId) { + return new AssociatedWithNetwork(networkId); + } + + /** + * + * @return always returns true. + */ + public static Predicate any() { + return Predicates.alwaysTrue(); + } +} diff --git a/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/AddressAsyncClientTest.java b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/AddressAsyncClientTest.java index 459038dcd5..ca687fb8ef 100644 --- a/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/AddressAsyncClientTest.java +++ b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/AddressAsyncClientTest.java @@ -22,6 +22,7 @@ package org.jclouds.cloudstack.features; import java.io.IOException; import java.lang.reflect.Method; +import org.jclouds.cloudstack.functions.ReturnVoidOnNotFoundOr404OrUnableToFindAccountOwner; import org.jclouds.cloudstack.options.AssociateIPAddressOptions; import org.jclouds.cloudstack.options.ListPublicIPAddressesOptions; import org.jclouds.http.HttpRequest; @@ -32,7 +33,6 @@ import org.jclouds.http.functions.UnwrapOnlyNestedJsonValueInSet; import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions; import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404; import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; -import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404; import org.jclouds.rest.internal.RestAnnotationProcessor; import org.testng.annotations.Test; @@ -131,7 +131,7 @@ public class AddressAsyncClientTest extends BaseCloudStackAsyncClientTest jobComplete; - - @BeforeGroups(groups = "live") - public void setupClient() { - super.setupClient(); - jobComplete = new RetryablePredicate(new JobComplete(client), 600, 5, TimeUnit.SECONDS); - } public void testAssociateDisassociatePublicIPAddress() throws Exception { - ip = createPublicIPAddress(client, jobComplete); + AsyncCreateResponse job = client.getAddressClient().associateIPAddress( + Iterables.get(client.getNetworkClient().listNetworks(), 0).getZoneId()); + checkState(jobComplete.apply(job.getJobId()), "job %d failed to complete", job.getJobId()); + ip = client.getAsyncJobClient(). getAsyncJob(job.getJobId()).getResult(); checkIP(ip); } - public static PublicIPAddress createPublicIPAddress(final CloudStackClient client, - RetryablePredicate jobComplete) { - Network network = find(client.getNetworkClient().listNetworks(), new Predicate() { - - @Override - public boolean apply(Network arg0) { - return Iterables.any(arg0.getServices(), new Predicate() { - - @Override - public boolean apply(NetworkService input) { - return input.getName().equals("Firewall") && "true".equals(input.getCapabilities().get("StaticNat")); - } - - }); - } - - @Override - public String toString() { - return "networkType(ADVANCED)"; - } - }); - return createPublicIPAddressInNetwork(network, client, jobComplete); - } - - public static PublicIPAddress createPublicIPAddressInNetwork(Network network, CloudStackClient client, - RetryablePredicate jobComplete) { - AsyncCreateResponse job = client.getAddressClient().associateIPAddress(network.getZoneId(), - AssociateIPAddressOptions.Builder.networkId(network.getId())); - assert jobComplete.apply(job.getJobId()); - PublicIPAddress ip = client.getAsyncJobClient(). getAsyncJob(job.getJobId()).getResult(); - assertEquals(ip.getZoneId(), network.getZoneId()); - return ip; - } - @AfterGroups(groups = "live") protected void tearDown() { if (ip != null) { diff --git a/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/AsyncJobClientLiveTest.java b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/AsyncJobClientLiveTest.java index 4b059f0aff..5a77b7f13a 100644 --- a/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/AsyncJobClientLiveTest.java +++ b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/AsyncJobClientLiveTest.java @@ -34,7 +34,8 @@ import org.testng.annotations.Test; */ @Test(groups = "live", sequential = true, testName = "AsyncJobClientLiveTest") public class AsyncJobClientLiveTest extends BaseCloudStackClientLiveTest { - + // disabled as it takes too long + @Test(enabled = false) public void testListAsyncJobs() throws Exception { Set> response = client.getAsyncJobClient().listAsyncJobs(); assert null != response; @@ -48,7 +49,7 @@ public class AsyncJobClientLiveTest extends BaseCloudStackClientLiveTest { AsyncJob query = client.getAsyncJobClient().getAsyncJob(asyncJob.getId()); assertEquals(query.getId(), asyncJob.getId()); - assert query.getResultType() != null :query; + assert query.getResultType() != null : query; checkJob(query); } } diff --git a/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/BaseCloudStackClientLiveTest.java b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/BaseCloudStackClientLiveTest.java index cbe49fa7b1..3ee91f7cd5 100644 --- a/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/BaseCloudStackClientLiveTest.java +++ b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/BaseCloudStackClientLiveTest.java @@ -29,6 +29,7 @@ import org.jclouds.Constants; import org.jclouds.cloudstack.CloudStackAsyncClient; import org.jclouds.cloudstack.CloudStackClient; import org.jclouds.cloudstack.domain.VirtualMachine; +import org.jclouds.cloudstack.functions.ReuseOrAssociateNewPublicIPAddress; import org.jclouds.cloudstack.predicates.JobComplete; import org.jclouds.cloudstack.predicates.VirtualMachineDestroyed; import org.jclouds.cloudstack.predicates.VirtualMachineRunning; @@ -48,6 +49,7 @@ import org.testng.annotations.BeforeGroups; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableSet; import com.google.inject.Guice; +import com.google.inject.Injector; import com.google.inject.Module; /** @@ -71,6 +73,10 @@ public class BaseCloudStackClientLiveTest { protected SshClient.Factory sshFactory; protected String password = "password"; + protected Injector injector; + + protected ReuseOrAssociateNewPublicIPAddress reuseOrAssociate; + protected void setupCredentials() { identity = checkNotNull(System.getProperty("test." + provider + ".identity"), "test." + provider + ".identity must be set. ex. apiKey"); @@ -115,13 +121,20 @@ public class BaseCloudStackClientLiveTest { overrides); client = context.getApi(); - sshFactory = Guice.createInjector(new JschSshClientModule()).getInstance(SshClient.Factory.class); - socketTester = new RetryablePredicate(new InetSocketAddressConnect(), 180, 1, TimeUnit.SECONDS); - jobComplete = new RetryablePredicate(new JobComplete(client), 600, 5, TimeUnit.SECONDS); - virtualMachineRunning = new RetryablePredicate(new VirtualMachineRunning(client), 600, 5, + injector = Guice.createInjector(new JschSshClientModule(),new Log4JLoggingModule()); + sshFactory = injector.getInstance(SshClient.Factory.class); + socketTester = new RetryablePredicate(new InetSocketAddressConnect(), 180, 1, 1, TimeUnit.SECONDS); + injector.injectMembers(socketTester); + jobComplete = new RetryablePredicate(new JobComplete(client), 600, 5, 5, TimeUnit.SECONDS); + injector.injectMembers(jobComplete); + virtualMachineRunning = new RetryablePredicate(new VirtualMachineRunning(client), 600, 5, 5, TimeUnit.SECONDS); - virtualMachineDestroyed = new RetryablePredicate(new VirtualMachineDestroyed(client), 600, 5, + injector.injectMembers(virtualMachineRunning); + virtualMachineDestroyed = new RetryablePredicate(new VirtualMachineDestroyed(client), 600, 5, 5, TimeUnit.SECONDS); + injector.injectMembers(virtualMachineDestroyed); + reuseOrAssociate = new ReuseOrAssociateNewPublicIPAddress(client, jobComplete); + injector.injectMembers(reuseOrAssociate); } @AfterGroups(groups = "live") diff --git a/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/FirewallClientLiveTest.java b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/FirewallClientLiveTest.java index e3570bfd8a..d6e58d1560 100644 --- a/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/FirewallClientLiveTest.java +++ b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/FirewallClientLiveTest.java @@ -26,13 +26,12 @@ import static org.testng.Assert.assertTrue; import java.util.Set; import org.jclouds.cloudstack.domain.AsyncCreateResponse; +import org.jclouds.cloudstack.domain.Network; import org.jclouds.cloudstack.domain.PortForwardingRule; import org.jclouds.cloudstack.domain.PublicIPAddress; import org.jclouds.cloudstack.domain.VirtualMachine; -import org.jclouds.compute.domain.ExecResponse; -import org.jclouds.domain.Credentials; +import org.jclouds.cloudstack.predicates.NetworkPredicates; import org.jclouds.net.IPSocket; -import org.jclouds.ssh.SshClient; import org.testng.annotations.AfterGroups; import org.testng.annotations.BeforeGroups; import org.testng.annotations.Test; @@ -49,38 +48,39 @@ public class FirewallClientLiveTest extends BaseCloudStackClientLiveTest { private PublicIPAddress ip = null; private VirtualMachine vm; private PortForwardingRule rule; + private Network network; @BeforeGroups(groups = "live") public void setupClient() { super.setupClient(); prefix += "rule"; - ip = AddressClientLiveTest.createPublicIPAddress(client, jobComplete); - vm = VirtualMachineClientLiveTest.createVirtualMachine(client, jobComplete, virtualMachineRunning); + network = find(client.getNetworkClient().listNetworks(), NetworkPredicates.supportsPortForwarding()); + vm = VirtualMachineClientLiveTest.createVirtualMachineInNetwork(network, client, jobComplete, + virtualMachineRunning); if (vm.getPassword() != null) password = vm.getPassword(); } public void testCreatePortForwardingRule() throws Exception { - AsyncCreateResponse job = client.getFirewallClient().createPortForwardingRuleForVirtualMachine(vm.getId(), - ip.getId(), "tcp", 22, 22); - assert jobComplete.apply(job.getJobId()); - rule = findRuleWithId(job.getId()); + + while (rule == null) { + ip = reuseOrAssociate.apply(network); + try { + AsyncCreateResponse job = client.getFirewallClient().createPortForwardingRuleForVirtualMachine(vm.getId(), + ip.getId(), "tcp", 22, 22); + assert jobComplete.apply(job.getJobId()); + rule = findRuleWithId(job.getId()); + } catch (IllegalStateException e) { + // very likely an ip conflict, so retry; + } + } + assertEquals(rule.getIPAddressId(), ip.getId()); assertEquals(rule.getVirtualMachineId(), vm.getId()); assertEquals(rule.getPublicPort(), 22); assertEquals(rule.getProtocol(), "tcp"); checkRule(rule); - IPSocket socket = new IPSocket(ip.getIPAddress(), 22); - socketTester.apply(socket); - SshClient client = sshFactory.create(socket, new Credentials("root", password)); - try { - client.connect(); - ExecResponse exec = client.exec("echo hello"); - assertEquals(exec.getOutput().trim(), "hello"); - } finally { - if (client != null) - client.disconnect(); - } + checkSSH(new IPSocket(ip.getIPAddress(), 22)); } @AfterGroups(groups = "live") @@ -88,12 +88,12 @@ public class FirewallClientLiveTest extends BaseCloudStackClientLiveTest { if (rule != null) { client.getFirewallClient().deletePortForwardingRule(rule.getId()); } + if (vm != null) { + jobComplete.apply(client.getVirtualMachineClient().destroyVirtualMachine(vm.getId())); + } if (ip != null) { client.getAddressClient().disassociateIPAddress(ip.getId()); } - if (vm != null) { - assert jobComplete.apply(client.getVirtualMachineClient().destroyVirtualMachine(vm.getId())); - } super.tearDown(); } diff --git a/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/LoadBalancerClientLiveTest.java b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/LoadBalancerClientLiveTest.java index c0d139ebfe..ffb1bc52a5 100644 --- a/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/LoadBalancerClientLiveTest.java +++ b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/LoadBalancerClientLiveTest.java @@ -23,17 +23,21 @@ import static com.google.common.collect.Iterables.find; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; +import java.io.IOException; import java.util.Set; import java.util.concurrent.TimeUnit; import org.jclouds.cloudstack.domain.LoadBalancerRule; +import org.jclouds.cloudstack.domain.Network; import org.jclouds.cloudstack.domain.PublicIPAddress; import org.jclouds.cloudstack.domain.VirtualMachine; import org.jclouds.cloudstack.domain.LoadBalancerRule.Algorithm; import org.jclouds.cloudstack.domain.LoadBalancerRule.State; import org.jclouds.cloudstack.predicates.LoadBalancerRuleActive; +import org.jclouds.cloudstack.predicates.NetworkPredicates; import org.jclouds.net.IPSocket; import org.jclouds.predicates.RetryablePredicate; +import org.jclouds.ssh.SshException; import org.testng.annotations.AfterGroups; import org.testng.annotations.BeforeGroups; import org.testng.annotations.Test; @@ -51,22 +55,32 @@ public class LoadBalancerClientLiveTest extends BaseCloudStackClientLiveTest { private VirtualMachine vm; private LoadBalancerRule rule; private RetryablePredicate loadBalancerRuleActive; + private Network network; @BeforeGroups(groups = "live") public void setupClient() { super.setupClient(); - loadBalancerRuleActive = new RetryablePredicate(new LoadBalancerRuleActive(client), 600, 5, + + loadBalancerRuleActive = new RetryablePredicate(new LoadBalancerRuleActive(client), 60, 1, 1, TimeUnit.SECONDS); prefix += "rule"; - ip = AddressClientLiveTest.createPublicIPAddress(client, jobComplete); - vm = VirtualMachineClientLiveTest.createVirtualMachine(client, jobComplete, virtualMachineRunning); + network = find(client.getNetworkClient().listNetworks(), NetworkPredicates.hasLoadBalancerService()); + vm = VirtualMachineClientLiveTest.createVirtualMachineInNetwork(network, client, jobComplete, + virtualMachineRunning); if (vm.getPassword() != null) password = vm.getPassword(); } public void testCreateLoadBalancerRule() throws Exception { - rule = client.getLoadBalancerClient().createLoadBalancerRuleForPublicIP(ip.getId(), Algorithm.LEASTCONN, prefix, - 22, 22); + while (rule == null) { + ip = reuseOrAssociate.apply(network); + try { + rule = client.getLoadBalancerClient().createLoadBalancerRuleForPublicIP(ip.getId(), Algorithm.LEASTCONN, + prefix, 22, 22); + } catch (IllegalStateException e) { + // very likely an ip conflict, so retry; + } + } assert (rule.getPublicIPId() == ip.getId()) : rule; assertEquals(rule.getPublicPort(), 22); assertEquals(rule.getPrivatePort(), 22); @@ -84,18 +98,33 @@ public class LoadBalancerClientLiveTest extends BaseCloudStackClientLiveTest { vm.getId())); assertEquals(client.getLoadBalancerClient().listVirtualMachinesAssignedToLoadBalancerRule(rule.getId()).size(), 1); assert loadBalancerRuleActive.apply(rule) : rule; - IPSocket socket = new IPSocket(ip.getIPAddress(), 22); - assert socketTester.apply(socket) : vm; + loopAndCheckSSH(); } - @Test(dependsOnMethods = "testAssignToLoadBalancerRule") + // note that when in LB mode, there's a chance you'll have a connection failure + private void loopAndCheckSSH() throws IOException { + for (int i = 0; i < 5; i++) {// retry loop TODO replace with predicate. + try { + checkSSH(new IPSocket(ip.getIPAddress(), 22)); + return; + } catch (SshException e) { + e.printStackTrace(); + try { + Thread.sleep(10 * 1000); + } catch (InterruptedException e1) { + } + continue; + } + } + } + + @Test(dependsOnMethods = "testAssignToLoadBalancerRule", expectedExceptions = SshException.class) public void testRemoveFromLoadBalancerRule() throws Exception { assert jobComplete.apply(client.getLoadBalancerClient().removeVirtualMachinesFromLoadBalancerRule(rule.getId(), vm.getId())); assertEquals(client.getLoadBalancerClient().listVirtualMachinesAssignedToLoadBalancerRule(rule.getId()).size(), 0); assertEquals(rule.getState(), State.ADD); - IPSocket socket = new IPSocket(ip.getIPAddress(), 22); - assert !socketTester.apply(socket); + checkSSH(new IPSocket(ip.getIPAddress(), 22)); } @AfterGroups(groups = "live") @@ -116,7 +145,7 @@ public class LoadBalancerClientLiveTest extends BaseCloudStackClientLiveTest { Set response = client.getLoadBalancerClient().listLoadBalancerRules(); assert null != response; assertTrue(response.size() >= 0); - for (final LoadBalancerRule rule : response) { + for (LoadBalancerRule rule : response) { LoadBalancerRule newDetails = findRuleWithId(rule.getId()); assertEquals(rule.getId(), newDetails.getId()); checkRule(rule); diff --git a/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/NATClientLiveTest.java b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/NATClientLiveTest.java index 5838a985d2..9786b52e05 100644 --- a/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/NATClientLiveTest.java +++ b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/NATClientLiveTest.java @@ -19,6 +19,7 @@ package org.jclouds.cloudstack.features; +import static com.google.common.collect.Iterables.find; import static com.google.common.collect.Iterables.getOnlyElement; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; @@ -27,9 +28,11 @@ import java.util.Set; import org.jclouds.cloudstack.domain.AsyncCreateResponse; import org.jclouds.cloudstack.domain.IPForwardingRule; +import org.jclouds.cloudstack.domain.Network; import org.jclouds.cloudstack.domain.PublicIPAddress; import org.jclouds.cloudstack.domain.VirtualMachine; import org.jclouds.cloudstack.options.ListIPForwardingRulesOptions; +import org.jclouds.cloudstack.predicates.NetworkPredicates; import org.jclouds.compute.domain.ExecResponse; import org.jclouds.domain.Credentials; import org.jclouds.net.IPSocket; @@ -48,23 +51,34 @@ public class NATClientLiveTest extends BaseCloudStackClientLiveTest { private PublicIPAddress ip = null; private VirtualMachine vm; private IPForwardingRule rule; + private Network network; @BeforeGroups(groups = "live") public void setupClient() { super.setupClient(); prefix += "nat"; - ip = AddressClientLiveTest.createPublicIPAddress(client, jobComplete); - vm = VirtualMachineClientLiveTest.createVirtualMachine(client, jobComplete, virtualMachineRunning); + network = find(client.getNetworkClient().listNetworks(), NetworkPredicates.supportsStaticNAT()); + vm = VirtualMachineClientLiveTest.createVirtualMachineInNetwork(network, client, jobComplete, + virtualMachineRunning); if (vm.getPassword() != null) password = vm.getPassword(); } public void testCreateIPForwardingRule() throws Exception { - - assert !ip.isStaticNAT(); - client.getNATClient().enableStaticNATForVirtualMachine(vm.getId(), ip.getId()); - ip = client.getAddressClient().getPublicIPAddress(ip.getId()); - assert ip.isStaticNAT(); + for (ip = reuseOrAssociate.apply(network); (!ip.isStaticNAT() || ip.getVirtualMachineId() != vm.getId()); ip = reuseOrAssociate + .apply(network)) { + // check to see if someone already grabbed this ip + if (ip.getVirtualMachineId() > 0 && ip.getVirtualMachineId() != vm.getId()) + continue; + try { + client.getNATClient().enableStaticNATForVirtualMachine(vm.getId(), ip.getId()); + ip = client.getAddressClient().getPublicIPAddress(ip.getId()); + if (ip.isStaticNAT() && ip.getVirtualMachineId() == vm.getId()) + break; + } catch (IllegalStateException e) { + // very likely an ip conflict, so retry; + } + } AsyncCreateResponse job = client.getNATClient().createIPForwardingRule(ip.getId(), "tcp", 22); assert jobComplete.apply(job.getJobId()); @@ -76,7 +90,7 @@ public class NATClientLiveTest extends BaseCloudStackClientLiveTest { checkRule(rule); IPSocket socket = new IPSocket(ip.getIPAddress(), 22); socketTester.apply(socket); - SshClient client = sshFactory.create(socket, new Credentials("root",password)); + SshClient client = sshFactory.create(socket, new Credentials("root", password)); try { client.connect(); ExecResponse exec = client.exec("echo hello"); @@ -92,22 +106,24 @@ public class NATClientLiveTest extends BaseCloudStackClientLiveTest { if (rule != null) { client.getNATClient().deleteIPForwardingRule(rule.getId()); } + if (vm != null) { + jobComplete.apply(client.getVirtualMachineClient().destroyVirtualMachine(vm.getId())); + } if (ip != null) { client.getAddressClient().disassociateIPAddress(ip.getId()); } - if (vm != null) { - assert jobComplete.apply(client.getVirtualMachineClient().destroyVirtualMachine(vm.getId())); - } super.tearDown(); } + @Test(enabled = false) + // takes too long public void testListIPForwardingRules() throws Exception { Set response = client.getNATClient().listIPForwardingRules(); assert null != response; assertTrue(response.size() >= 0); for (IPForwardingRule rule : response) { IPForwardingRule newDetails = getOnlyElement(client.getNATClient().listIPForwardingRules( - ListIPForwardingRulesOptions.Builder.id(rule.getId()))); + ListIPForwardingRulesOptions.Builder.id(rule.getId()))); assertEquals(rule.getId(), newDetails.getId()); checkRule(rule); } diff --git a/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/VirtualMachineClientLiveTest.java b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/VirtualMachineClientLiveTest.java index fb0f4027b5..7c9e17964e 100644 --- a/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/VirtualMachineClientLiveTest.java +++ b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/VirtualMachineClientLiveTest.java @@ -30,9 +30,11 @@ import static org.testng.Assert.assertTrue; import java.util.NoSuchElementException; import java.util.Set; +import java.util.concurrent.ExecutionException; import org.jclouds.cloudstack.CloudStackClient; import org.jclouds.cloudstack.domain.AsyncCreateResponse; +import org.jclouds.cloudstack.domain.AsyncJob; import org.jclouds.cloudstack.domain.GuestIPType; import org.jclouds.cloudstack.domain.NIC; import org.jclouds.cloudstack.domain.Network; @@ -49,6 +51,7 @@ import org.testng.annotations.AfterGroups; import org.testng.annotations.Test; import com.google.common.base.Predicate; +import com.google.common.base.Throwables; import com.google.common.collect.ComparisonChain; import com.google.common.collect.Iterables; import com.google.common.collect.Ordering; @@ -140,7 +143,13 @@ public class VirtualMachineClientLiveTest extends BaseCloudStackClientLiveTest { AsyncCreateResponse job = client.getVirtualMachineClient().deployVirtualMachine(serviceOfferingId, templateId, zoneId, options); assert jobComplete.apply(job.getJobId()); - VirtualMachine vm = client.getAsyncJobClient(). getAsyncJob(job.getJobId()).getResult(); + AsyncJob jobWithResult = client.getAsyncJobClient(). getAsyncJob(job.getJobId()); + if (jobWithResult.getError() != null) + Throwables.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(); if (vm.isPasswordEnabled()) { assert vm.getPassword() != null : vm; } diff --git a/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/functions/ReuseOrAssociateNewPublicIPAddressTest.java b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/functions/ReuseOrAssociateNewPublicIPAddressTest.java new file mode 100644 index 0000000000..a844196eca --- /dev/null +++ b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/functions/ReuseOrAssociateNewPublicIPAddressTest.java @@ -0,0 +1,154 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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.cloudstack.functions; + +import static org.easymock.EasyMock.expect; +import static org.easymock.classextension.EasyMock.createMock; +import static org.easymock.classextension.EasyMock.replay; +import static org.easymock.classextension.EasyMock.verify; +import static org.jclouds.cloudstack.options.AssociateIPAddressOptions.Builder.networkId; +import static org.jclouds.cloudstack.options.ListPublicIPAddressesOptions.Builder.allocatedOnly; +import static org.testng.Assert.assertEquals; + +import org.jclouds.cloudstack.CloudStackClient; +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.features.AddressClient; +import org.jclouds.cloudstack.features.AsyncJobClient; +import org.testng.annotations.Test; + +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.collect.ImmutableSet; + +/** + * @author Adrian Cole + */ +@Test(groups = "unit") +public class ReuseOrAssociateNewPublicIPAddressTest { + long networkId = 99l; + long zoneId = 100l; + // note that it is associated network, not networkId + PublicIPAddress address = PublicIPAddress.builder().id(200).state(PublicIPAddress.State.ALLOCATED) + .associatedNetworkId(networkId).zoneId(zoneId).build(); + + public void testReuseWorks() throws SecurityException, NoSuchMethodException { + + // create mocks + CloudStackClient client = createMock(CloudStackClient.class); + Predicate jobComplete = Predicates.alwaysTrue(); + AddressClient addressClient = createMock(AddressClient.class); + expect(client.getAddressClient()).andReturn(addressClient).atLeastOnce(); + + // an address is available + expect(addressClient.listPublicIPAddresses(allocatedOnly(true).networkId(networkId))).andReturn( + ImmutableSet. of(address)); + + // replay mocks + replay(client); + replay(addressClient); + + // run + assertEquals(new ReuseOrAssociateNewPublicIPAddress(client, jobComplete).apply(Network.builder().id(networkId) + .zoneId(zoneId).build()), address); + + // verify mocks + verify(client); + verify(addressClient); + + } + + public void testAssociateWorks() throws SecurityException, NoSuchMethodException { + long networkId = 99l; + long zoneId = 100l; + + // create mocks + CloudStackClient client = createMock(CloudStackClient.class); + Predicate jobComplete = Predicates.alwaysTrue(); + AddressClient addressClient = createMock(AddressClient.class); + expect(client.getAddressClient()).andReturn(addressClient).atLeastOnce(); + + // no ip addresses available + expect(addressClient.listPublicIPAddresses(allocatedOnly(true).networkId(networkId))).andReturn( + ImmutableSet. of()); + + AsyncCreateResponse job = new AsyncCreateResponse(1, 2); + // make sure we created the job relating to a new ip + expect(addressClient.associateIPAddress(zoneId, networkId(networkId))).andReturn(job); + + AsyncJobClient jobClient = createMock(AsyncJobClient.class); + expect(client.getAsyncJobClient()).andReturn(jobClient).atLeastOnce(); + + expect(jobClient.getAsyncJob(2)).andReturn(AsyncJob.builder().result(address).build()); + + // replay mocks + replay(client); + replay(addressClient); + replay(jobClient); + + // run + assertEquals(new ReuseOrAssociateNewPublicIPAddress(client, jobComplete).apply(Network.builder().id(networkId) + .zoneId(zoneId).build()), address); + + // verify mocks + verify(client); + verify(addressClient); + verify(jobClient); + + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testJobDoesntCompleteThrowsIllegalStateException() throws SecurityException, NoSuchMethodException { + long networkId = 99l; + long zoneId = 100l; + + // create mocks + CloudStackClient client = createMock(CloudStackClient.class); + Predicate jobComplete = Predicates.alwaysFalse(); + AddressClient addressClient = createMock(AddressClient.class); + expect(client.getAddressClient()).andReturn(addressClient).atLeastOnce(); + + // no ip addresses available + expect(addressClient.listPublicIPAddresses(allocatedOnly(true).networkId(networkId))).andReturn( + ImmutableSet. of()); + + AsyncCreateResponse job = new AsyncCreateResponse(1, 2); + // make sure we created the job relating to a new ip + expect(addressClient.associateIPAddress(zoneId, networkId(networkId))).andReturn(job); + + // the alwaysfalse predicate above should blow up with IllegalStateException + + // replay mocks + replay(client); + replay(addressClient); + + // run + new ReuseOrAssociateNewPublicIPAddress(client, jobComplete).apply(Network.builder().id(networkId).zoneId(zoneId) + .build()); + + // verify mocks + verify(client); + verify(addressClient); + + } + +} diff --git a/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/predicates/NetworkPredicatesTest.java b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/predicates/NetworkPredicatesTest.java new file mode 100644 index 0000000000..9625461b86 --- /dev/null +++ b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/predicates/NetworkPredicatesTest.java @@ -0,0 +1,88 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious) LLC. + * + * ==================================================================== + * 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.cloudstack.predicates; + +import static org.jclouds.cloudstack.predicates.NetworkPredicates.hasLoadBalancerService; +import static org.jclouds.cloudstack.predicates.NetworkPredicates.supportsPortForwarding; +import static org.jclouds.cloudstack.predicates.NetworkPredicates.supportsStaticNAT; + +import org.jclouds.cloudstack.domain.Network; +import org.jclouds.cloudstack.domain.NetworkService; +import org.testng.annotations.Test; + +import com.google.common.base.Predicates; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +/** + * + * @author Adrian Cole + */ +@Test(groups = "unit") +public class NetworkPredicatesTest { + + public void testHasLoadBalancerService() { + Network network = Network.builder().id(204).services(ImmutableSet.of(new NetworkService("Lb"))).build(); + + assert hasLoadBalancerService().apply(network); + assert !supportsStaticNAT().apply(network); + assert !supportsPortForwarding().apply(network); + + } + + public void testSupportsStaticNATFindsWhenFirewallHasStaticNatFeature() { + Network network = Network.builder().id(204).services( + ImmutableSet.of(new NetworkService("Firewall", ImmutableMap. of("StaticNat", "true")))) + .build(); + + assert !hasLoadBalancerService().apply(network); + assert supportsStaticNAT().apply(network); + assert !supportsPortForwarding().apply(network); + } + + public void testNoSupport() { + Network network = Network.builder().id(204).services( + ImmutableSet.of(new NetworkService("Firewall", ImmutableMap. of()))).build(); + + assert !hasLoadBalancerService().apply(network); + assert !supportsStaticNAT().apply(network); + assert !supportsPortForwarding().apply(network); + } + + public void testSupportsPortForwardingFindsWhenFirewallHasPortForwardingFeature() { + Network network = Network.builder().id(204).services( + ImmutableSet.of(new NetworkService("Firewall", ImmutableMap + . of("PortForwarding", "true")))).build(); + + assert !hasLoadBalancerService().apply(network); + assert !supportsStaticNAT().apply(network); + assert supportsPortForwarding().apply(network); + } + + public void testSupportsPortForwardingAndStaticNATWhenFirewallHasFeatures() { + Network network = Network.builder().id(204).services( + ImmutableSet.of(new NetworkService("Firewall", ImmutableMap. of("StaticNat", "true", + "PortForwarding", "true")))).build(); + + assert Predicates.and(supportsPortForwarding(), supportsStaticNAT()).apply(network); + assert !hasLoadBalancerService().apply(network); + + } +} diff --git a/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/predicates/PublicIPAddressPredicatesTest.java b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/predicates/PublicIPAddressPredicatesTest.java new file mode 100644 index 0000000000..132d93f977 --- /dev/null +++ b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/predicates/PublicIPAddressPredicatesTest.java @@ -0,0 +1,71 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious) LLC. + * + * ==================================================================== + * 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.cloudstack.predicates; + +import static org.jclouds.cloudstack.predicates.PublicIPAddressPredicates.available; + +import org.jclouds.cloudstack.domain.PublicIPAddress; +import org.testng.annotations.Test; + +/** + * + * @author Adrian Cole + */ +@Test(groups = "unit") +public class PublicIPAddressPredicatesTest { + + public void testIsAvailableWhenAllocated() { + PublicIPAddress address = PublicIPAddress.builder().state(PublicIPAddress.State.ALLOCATED).id(204).build(); + + assert available().apply(address); + + } + + public void testIsNotAvailableWhenNotAllocated() { + PublicIPAddress address = PublicIPAddress.builder().state(PublicIPAddress.State.ALLOCATING).id(204).build(); + + assert !available().apply(address); + + } + + public void testIsNotAvailableWhenAssignedToVM() { + PublicIPAddress address = PublicIPAddress.builder().state(PublicIPAddress.State.ALLOCATED).virtualMachineId(1) + .id(204).build(); + + assert !available().apply(address); + + } + + public void testIsNotAvailableWhenSourceNAT() { + PublicIPAddress address = PublicIPAddress.builder().state(PublicIPAddress.State.ALLOCATED).isSourceNAT(true).id( + 204).build(); + + assert !available().apply(address); + + } + + public void testIsNotAvailableWhenStaticNAT() { + PublicIPAddress address = PublicIPAddress.builder().state(PublicIPAddress.State.ALLOCATED).isStaticNAT(true).id( + 204).build(); + + assert !available().apply(address); + + } +} diff --git a/sandbox-apis/cloudstack/src/test/resources/log4j.xml b/sandbox-apis/cloudstack/src/test/resources/log4j.xml index 7343ec00e2..590fc3093e 100644 --- a/sandbox-apis/cloudstack/src/test/resources/log4j.xml +++ b/sandbox-apis/cloudstack/src/test/resources/log4j.xml @@ -146,7 +146,7 @@ - +