added function to obtain a new ip or reuse

This commit is contained in:
Adrian Cole 2011-02-27 21:01:07 -08:00
parent 0e794c4788
commit e8038f5d48
20 changed files with 885 additions and 114 deletions

View File

@ -51,7 +51,7 @@
<properties> <properties>
<test.cloudstack.endpoint>http://localhost:8080/client/api</test.cloudstack.endpoint> <test.cloudstack.endpoint>http://localhost:8080/client/api</test.cloudstack.endpoint>
<test.cloudstack.apiversion>2.2</test.cloudstack.apiversion> <test.cloudstack.apiversion>2.2.0</test.cloudstack.apiversion>
<test.cloudstack.identity>FIXME_apiKey</test.cloudstack.identity> <test.cloudstack.identity>FIXME_apiKey</test.cloudstack.identity>
<test.cloudstack.credential>FIXME_secretKey</test.cloudstack.credential> <test.cloudstack.credential>FIXME_secretKey</test.cloudstack.credential>
</properties> </properties>
@ -68,6 +68,18 @@
<type>test-jar</type> <type>test-jar</type>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-compute</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-compute</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.jclouds.driver</groupId> <groupId>org.jclouds.driver</groupId>
<artifactId>jclouds-jsch</artifactId> <artifactId>jclouds-jsch</artifactId>
@ -108,6 +120,8 @@
<goal>test</goal> <goal>test</goal>
</goals> </goals>
<configuration> <configuration>
<!-- too many tasks seem to overload the server and make the test take longer -->
<threadCount>2</threadCount>
<systemProperties> <systemProperties>
<property> <property>
<name>test.cloudstack.endpoint</name> <name>test.cloudstack.endpoint</name>

View File

@ -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 * @return id of the resource being created
*/ */

View File

@ -29,6 +29,7 @@ import javax.ws.rs.core.MediaType;
import org.jclouds.cloudstack.domain.AsyncCreateResponse; import org.jclouds.cloudstack.domain.AsyncCreateResponse;
import org.jclouds.cloudstack.domain.PublicIPAddress; import org.jclouds.cloudstack.domain.PublicIPAddress;
import org.jclouds.cloudstack.filters.QuerySigner; import org.jclouds.cloudstack.filters.QuerySigner;
import org.jclouds.cloudstack.functions.ReturnVoidOnNotFoundOr404OrUnableToFindAccountOwner;
import org.jclouds.cloudstack.options.AssociateIPAddressOptions; import org.jclouds.cloudstack.options.AssociateIPAddressOptions;
import org.jclouds.cloudstack.options.ListPublicIPAddressesOptions; import org.jclouds.cloudstack.options.ListPublicIPAddressesOptions;
import org.jclouds.rest.annotations.ExceptionParser; 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.annotations.Unwrap;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404; import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
@ -88,7 +88,7 @@ public interface AddressAsyncClient {
*/ */
@GET @GET
@QueryParams(keys = "command", values = "disassociateIpAddress") @QueryParams(keys = "command", values = "disassociateIpAddress")
@ExceptionParser(ReturnVoidOnNotFoundOr404.class) @ExceptionParser(ReturnVoidOnNotFoundOr404OrUnableToFindAccountOwner.class)
ListenableFuture<Void> disassociateIPAddress(@QueryParam("id") long id); ListenableFuture<Void> disassociateIPAddress(@QueryParam("id") long id);
} }

View File

@ -0,0 +1,57 @@
/**
*
* Copyright (C) 2010 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.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<Exception, Void> {
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);
}
}
}

View File

@ -0,0 +1,108 @@
/**
*
* Copyright (C) 2010 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.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<Network, PublicIPAddress> {
private final CloudStackClient client;
private final Predicate<Long> jobComplete;
@Resource
@Named(COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
@Inject
public
ReuseOrAssociateNewPublicIPAddress(CloudStackClient client, Predicate<Long> 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<Long> 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().<PublicIPAddress> 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;
}
}
}

View File

@ -21,6 +21,8 @@ package org.jclouds.cloudstack.predicates;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.util.concurrent.ExecutionException;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Singleton; import javax.inject.Singleton;
@ -29,6 +31,7 @@ import org.jclouds.cloudstack.domain.AsyncJob;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Throwables;
import com.google.inject.Inject; import com.google.inject.Inject;
/** /**
@ -52,14 +55,19 @@ public class JobComplete implements Predicate<Long> {
public boolean apply(Long jobId) { public boolean apply(Long jobId) {
logger.trace("looking for status on job %s", checkNotNull(jobId, "jobId")); logger.trace("looking for status on job %s", checkNotNull(jobId, "jobId"));
AsyncJob job = refresh(jobId); AsyncJob<?> job = refresh(jobId);
if (job == null) if (job == null)
return false; return false;
logger.trace("%s: looking for job status %s: currently: %s", job.getId(), 1, job.getStatus()); 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; return job.getStatus() > 0;
} }
private AsyncJob refresh(Long jobId) { private AsyncJob<?> refresh(Long jobId) {
return client.getAsyncJobClient().getAsyncJob(jobId); return client.getAsyncJobClient().getAsyncJob(jobId);
} }
} }

View File

@ -0,0 +1,154 @@
/**
*
* Copyright (C) 2010 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.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<Network> {
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<Network> {
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<Network> {
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<NetworkService> {
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<NetworkService> {
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<NetworkService> supportsStaticNAT = Predicates.and(new NetworkServiceNamed("Firewall"),
new CapabilitiesInclude("StaticNat"));
public static Predicate<NetworkService> supportsPortForwarding = Predicates.and(new NetworkServiceNamed("Firewall"),
new CapabilitiesInclude("PortForwarding"));
public static Predicate<NetworkService> isLoadBalancerService = new NetworkServiceNamed("Lb");
/**
*
* @return true, if the network supports static NAT.
*/
public static Predicate<Network> supportsStaticNAT() {
return HasFirewallServiceWhichSupportsStaticNAT.INSTANCE;
}
/**
*
* @return true, if the network supports port forwarding.
*/
public static Predicate<Network> supportsPortForwarding() {
return HasFirewallServiceWhichSupportsPortForwarding.INSTANCE;
}
/**
*
* @return true, if the network supports load balancing.
*/
public static Predicate<Network> hasLoadBalancerService() {
return HasLoadBalancerService.INSTANCE;
}
/**
*
* @return always returns true.
*/
public static Predicate<Network> any() {
return Predicates.alwaysTrue();
}
}

View File

@ -0,0 +1,91 @@
/**
*
* Copyright (C) 2010 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.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<PublicIPAddress> {
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<PublicIPAddress> {
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<PublicIPAddress> available() {
return Available.INSTANCE;
}
/**
*
* @return true, if the public ip address is associated with the specified network
*/
public static Predicate<PublicIPAddress> associatedWithNetwork(final long networkId) {
return new AssociatedWithNetwork(networkId);
}
/**
*
* @return always returns true.
*/
public static Predicate<PublicIPAddress> any() {
return Predicates.alwaysTrue();
}
}

View File

@ -22,6 +22,7 @@ package org.jclouds.cloudstack.features;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import org.jclouds.cloudstack.functions.ReturnVoidOnNotFoundOr404OrUnableToFindAccountOwner;
import org.jclouds.cloudstack.options.AssociateIPAddressOptions; import org.jclouds.cloudstack.options.AssociateIPAddressOptions;
import org.jclouds.cloudstack.options.ListPublicIPAddressesOptions; import org.jclouds.cloudstack.options.ListPublicIPAddressesOptions;
import org.jclouds.http.HttpRequest; 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.MapHttp4xxCodesToExceptions;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404; import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
import org.jclouds.rest.internal.RestAnnotationProcessor; import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -131,7 +131,7 @@ public class AddressAsyncClientTest extends BaseCloudStackAsyncClientTest<Addres
assertResponseParserClassEquals(method, httpRequest, ReleasePayloadAndReturn.class); assertResponseParserClassEquals(method, httpRequest, ReleasePayloadAndReturn.class);
assertSaxResponseParserClassEquals(method, null); assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnVoidOnNotFoundOr404.class); assertExceptionParserClassEquals(method, ReturnVoidOnNotFoundOr404OrUnableToFindAccountOwner.class);
checkFilters(httpRequest); checkFilters(httpRequest);

View File

@ -19,28 +19,19 @@
package org.jclouds.cloudstack.features; package org.jclouds.cloudstack.features;
import static com.google.common.collect.Iterables.find; import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.getOnlyElement; import static com.google.common.collect.Iterables.getOnlyElement;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertTrue;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.jclouds.cloudstack.CloudStackClient;
import org.jclouds.cloudstack.domain.AsyncCreateResponse; import org.jclouds.cloudstack.domain.AsyncCreateResponse;
import org.jclouds.cloudstack.domain.Network;
import org.jclouds.cloudstack.domain.NetworkService;
import org.jclouds.cloudstack.domain.PublicIPAddress; import org.jclouds.cloudstack.domain.PublicIPAddress;
import org.jclouds.cloudstack.options.AssociateIPAddressOptions;
import org.jclouds.cloudstack.options.ListPublicIPAddressesOptions; import org.jclouds.cloudstack.options.ListPublicIPAddressesOptions;
import org.jclouds.cloudstack.predicates.JobComplete;
import org.jclouds.predicates.RetryablePredicate;
import org.testng.annotations.AfterGroups; import org.testng.annotations.AfterGroups;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
/** /**
@ -51,53 +42,15 @@ import com.google.common.collect.Iterables;
@Test(groups = "live", sequential = true, testName = "PublicIPAddressClientLiveTest") @Test(groups = "live", sequential = true, testName = "PublicIPAddressClientLiveTest")
public class AddressClientLiveTest extends BaseCloudStackClientLiveTest { public class AddressClientLiveTest extends BaseCloudStackClientLiveTest {
private PublicIPAddress ip = null; private PublicIPAddress ip = null;
private RetryablePredicate<Long> jobComplete;
@BeforeGroups(groups = "live")
public void setupClient() {
super.setupClient();
jobComplete = new RetryablePredicate<Long>(new JobComplete(client), 600, 5, TimeUnit.SECONDS);
}
public void testAssociateDisassociatePublicIPAddress() throws Exception { 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().<PublicIPAddress> getAsyncJob(job.getJobId()).getResult();
checkIP(ip); checkIP(ip);
} }
public static PublicIPAddress createPublicIPAddress(final CloudStackClient client,
RetryablePredicate<Long> jobComplete) {
Network network = find(client.getNetworkClient().listNetworks(), new Predicate<Network>() {
@Override
public boolean apply(Network arg0) {
return Iterables.any(arg0.getServices(), new Predicate<NetworkService>() {
@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<Long> jobComplete) {
AsyncCreateResponse job = client.getAddressClient().associateIPAddress(network.getZoneId(),
AssociateIPAddressOptions.Builder.networkId(network.getId()));
assert jobComplete.apply(job.getJobId());
PublicIPAddress ip = client.getAsyncJobClient().<PublicIPAddress> getAsyncJob(job.getJobId()).getResult();
assertEquals(ip.getZoneId(), network.getZoneId());
return ip;
}
@AfterGroups(groups = "live") @AfterGroups(groups = "live")
protected void tearDown() { protected void tearDown() {
if (ip != null) { if (ip != null) {

View File

@ -34,7 +34,8 @@ import org.testng.annotations.Test;
*/ */
@Test(groups = "live", sequential = true, testName = "AsyncJobClientLiveTest") @Test(groups = "live", sequential = true, testName = "AsyncJobClientLiveTest")
public class AsyncJobClientLiveTest extends BaseCloudStackClientLiveTest { public class AsyncJobClientLiveTest extends BaseCloudStackClientLiveTest {
// disabled as it takes too long
@Test(enabled = false)
public void testListAsyncJobs() throws Exception { public void testListAsyncJobs() throws Exception {
Set<AsyncJob<?>> response = client.getAsyncJobClient().listAsyncJobs(); Set<AsyncJob<?>> response = client.getAsyncJobClient().listAsyncJobs();
assert null != response; assert null != response;
@ -48,7 +49,7 @@ public class AsyncJobClientLiveTest extends BaseCloudStackClientLiveTest {
AsyncJob<?> query = client.getAsyncJobClient().getAsyncJob(asyncJob.getId()); AsyncJob<?> query = client.getAsyncJobClient().getAsyncJob(asyncJob.getId());
assertEquals(query.getId(), asyncJob.getId()); assertEquals(query.getId(), asyncJob.getId());
assert query.getResultType() != null :query; assert query.getResultType() != null : query;
checkJob(query); checkJob(query);
} }
} }

View File

@ -29,6 +29,7 @@ import org.jclouds.Constants;
import org.jclouds.cloudstack.CloudStackAsyncClient; import org.jclouds.cloudstack.CloudStackAsyncClient;
import org.jclouds.cloudstack.CloudStackClient; import org.jclouds.cloudstack.CloudStackClient;
import org.jclouds.cloudstack.domain.VirtualMachine; import org.jclouds.cloudstack.domain.VirtualMachine;
import org.jclouds.cloudstack.functions.ReuseOrAssociateNewPublicIPAddress;
import org.jclouds.cloudstack.predicates.JobComplete; import org.jclouds.cloudstack.predicates.JobComplete;
import org.jclouds.cloudstack.predicates.VirtualMachineDestroyed; import org.jclouds.cloudstack.predicates.VirtualMachineDestroyed;
import org.jclouds.cloudstack.predicates.VirtualMachineRunning; 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.base.Predicate;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module; import com.google.inject.Module;
/** /**
@ -71,6 +73,10 @@ public class BaseCloudStackClientLiveTest {
protected SshClient.Factory sshFactory; protected SshClient.Factory sshFactory;
protected String password = "password"; protected String password = "password";
protected Injector injector;
protected ReuseOrAssociateNewPublicIPAddress reuseOrAssociate;
protected void setupCredentials() { protected void setupCredentials() {
identity = checkNotNull(System.getProperty("test." + provider + ".identity"), "test." + provider identity = checkNotNull(System.getProperty("test." + provider + ".identity"), "test." + provider
+ ".identity must be set. ex. apiKey"); + ".identity must be set. ex. apiKey");
@ -115,13 +121,20 @@ public class BaseCloudStackClientLiveTest {
overrides); overrides);
client = context.getApi(); client = context.getApi();
sshFactory = Guice.createInjector(new JschSshClientModule()).getInstance(SshClient.Factory.class); injector = Guice.createInjector(new JschSshClientModule(),new Log4JLoggingModule());
socketTester = new RetryablePredicate<IPSocket>(new InetSocketAddressConnect(), 180, 1, TimeUnit.SECONDS); sshFactory = injector.getInstance(SshClient.Factory.class);
jobComplete = new RetryablePredicate<Long>(new JobComplete(client), 600, 5, TimeUnit.SECONDS); socketTester = new RetryablePredicate<IPSocket>(new InetSocketAddressConnect(), 180, 1, 1, TimeUnit.SECONDS);
virtualMachineRunning = new RetryablePredicate<VirtualMachine>(new VirtualMachineRunning(client), 600, 5, injector.injectMembers(socketTester);
jobComplete = new RetryablePredicate<Long>(new JobComplete(client), 600, 5, 5, TimeUnit.SECONDS);
injector.injectMembers(jobComplete);
virtualMachineRunning = new RetryablePredicate<VirtualMachine>(new VirtualMachineRunning(client), 600, 5, 5,
TimeUnit.SECONDS); TimeUnit.SECONDS);
virtualMachineDestroyed = new RetryablePredicate<VirtualMachine>(new VirtualMachineDestroyed(client), 600, 5, injector.injectMembers(virtualMachineRunning);
virtualMachineDestroyed = new RetryablePredicate<VirtualMachine>(new VirtualMachineDestroyed(client), 600, 5, 5,
TimeUnit.SECONDS); TimeUnit.SECONDS);
injector.injectMembers(virtualMachineDestroyed);
reuseOrAssociate = new ReuseOrAssociateNewPublicIPAddress(client, jobComplete);
injector.injectMembers(reuseOrAssociate);
} }
@AfterGroups(groups = "live") @AfterGroups(groups = "live")

View File

@ -26,13 +26,12 @@ import static org.testng.Assert.assertTrue;
import java.util.Set; import java.util.Set;
import org.jclouds.cloudstack.domain.AsyncCreateResponse; import org.jclouds.cloudstack.domain.AsyncCreateResponse;
import org.jclouds.cloudstack.domain.Network;
import org.jclouds.cloudstack.domain.PortForwardingRule; import org.jclouds.cloudstack.domain.PortForwardingRule;
import org.jclouds.cloudstack.domain.PublicIPAddress; import org.jclouds.cloudstack.domain.PublicIPAddress;
import org.jclouds.cloudstack.domain.VirtualMachine; import org.jclouds.cloudstack.domain.VirtualMachine;
import org.jclouds.compute.domain.ExecResponse; import org.jclouds.cloudstack.predicates.NetworkPredicates;
import org.jclouds.domain.Credentials;
import org.jclouds.net.IPSocket; import org.jclouds.net.IPSocket;
import org.jclouds.ssh.SshClient;
import org.testng.annotations.AfterGroups; import org.testng.annotations.AfterGroups;
import org.testng.annotations.BeforeGroups; import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -49,38 +48,39 @@ public class FirewallClientLiveTest extends BaseCloudStackClientLiveTest {
private PublicIPAddress ip = null; private PublicIPAddress ip = null;
private VirtualMachine vm; private VirtualMachine vm;
private PortForwardingRule rule; private PortForwardingRule rule;
private Network network;
@BeforeGroups(groups = "live") @BeforeGroups(groups = "live")
public void setupClient() { public void setupClient() {
super.setupClient(); super.setupClient();
prefix += "rule"; prefix += "rule";
ip = AddressClientLiveTest.createPublicIPAddress(client, jobComplete); network = find(client.getNetworkClient().listNetworks(), NetworkPredicates.supportsPortForwarding());
vm = VirtualMachineClientLiveTest.createVirtualMachine(client, jobComplete, virtualMachineRunning); vm = VirtualMachineClientLiveTest.createVirtualMachineInNetwork(network, client, jobComplete,
virtualMachineRunning);
if (vm.getPassword() != null) if (vm.getPassword() != null)
password = vm.getPassword(); password = vm.getPassword();
} }
public void testCreatePortForwardingRule() throws Exception { public void testCreatePortForwardingRule() throws Exception {
AsyncCreateResponse job = client.getFirewallClient().createPortForwardingRuleForVirtualMachine(vm.getId(),
ip.getId(), "tcp", 22, 22); while (rule == null) {
assert jobComplete.apply(job.getJobId()); ip = reuseOrAssociate.apply(network);
rule = findRuleWithId(job.getId()); 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.getIPAddressId(), ip.getId());
assertEquals(rule.getVirtualMachineId(), vm.getId()); assertEquals(rule.getVirtualMachineId(), vm.getId());
assertEquals(rule.getPublicPort(), 22); assertEquals(rule.getPublicPort(), 22);
assertEquals(rule.getProtocol(), "tcp"); assertEquals(rule.getProtocol(), "tcp");
checkRule(rule); checkRule(rule);
IPSocket socket = new IPSocket(ip.getIPAddress(), 22); checkSSH(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();
}
} }
@AfterGroups(groups = "live") @AfterGroups(groups = "live")
@ -88,12 +88,12 @@ public class FirewallClientLiveTest extends BaseCloudStackClientLiveTest {
if (rule != null) { if (rule != null) {
client.getFirewallClient().deletePortForwardingRule(rule.getId()); client.getFirewallClient().deletePortForwardingRule(rule.getId());
} }
if (vm != null) {
jobComplete.apply(client.getVirtualMachineClient().destroyVirtualMachine(vm.getId()));
}
if (ip != null) { if (ip != null) {
client.getAddressClient().disassociateIPAddress(ip.getId()); client.getAddressClient().disassociateIPAddress(ip.getId());
} }
if (vm != null) {
assert jobComplete.apply(client.getVirtualMachineClient().destroyVirtualMachine(vm.getId()));
}
super.tearDown(); super.tearDown();
} }

View File

@ -23,17 +23,21 @@ import static com.google.common.collect.Iterables.find;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertTrue;
import java.io.IOException;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.jclouds.cloudstack.domain.LoadBalancerRule; import org.jclouds.cloudstack.domain.LoadBalancerRule;
import org.jclouds.cloudstack.domain.Network;
import org.jclouds.cloudstack.domain.PublicIPAddress; import org.jclouds.cloudstack.domain.PublicIPAddress;
import org.jclouds.cloudstack.domain.VirtualMachine; import org.jclouds.cloudstack.domain.VirtualMachine;
import org.jclouds.cloudstack.domain.LoadBalancerRule.Algorithm; import org.jclouds.cloudstack.domain.LoadBalancerRule.Algorithm;
import org.jclouds.cloudstack.domain.LoadBalancerRule.State; import org.jclouds.cloudstack.domain.LoadBalancerRule.State;
import org.jclouds.cloudstack.predicates.LoadBalancerRuleActive; import org.jclouds.cloudstack.predicates.LoadBalancerRuleActive;
import org.jclouds.cloudstack.predicates.NetworkPredicates;
import org.jclouds.net.IPSocket; import org.jclouds.net.IPSocket;
import org.jclouds.predicates.RetryablePredicate; import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.ssh.SshException;
import org.testng.annotations.AfterGroups; import org.testng.annotations.AfterGroups;
import org.testng.annotations.BeforeGroups; import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -51,22 +55,32 @@ public class LoadBalancerClientLiveTest extends BaseCloudStackClientLiveTest {
private VirtualMachine vm; private VirtualMachine vm;
private LoadBalancerRule rule; private LoadBalancerRule rule;
private RetryablePredicate<LoadBalancerRule> loadBalancerRuleActive; private RetryablePredicate<LoadBalancerRule> loadBalancerRuleActive;
private Network network;
@BeforeGroups(groups = "live") @BeforeGroups(groups = "live")
public void setupClient() { public void setupClient() {
super.setupClient(); super.setupClient();
loadBalancerRuleActive = new RetryablePredicate<LoadBalancerRule>(new LoadBalancerRuleActive(client), 600, 5,
loadBalancerRuleActive = new RetryablePredicate<LoadBalancerRule>(new LoadBalancerRuleActive(client), 60, 1, 1,
TimeUnit.SECONDS); TimeUnit.SECONDS);
prefix += "rule"; prefix += "rule";
ip = AddressClientLiveTest.createPublicIPAddress(client, jobComplete); network = find(client.getNetworkClient().listNetworks(), NetworkPredicates.hasLoadBalancerService());
vm = VirtualMachineClientLiveTest.createVirtualMachine(client, jobComplete, virtualMachineRunning); vm = VirtualMachineClientLiveTest.createVirtualMachineInNetwork(network, client, jobComplete,
virtualMachineRunning);
if (vm.getPassword() != null) if (vm.getPassword() != null)
password = vm.getPassword(); password = vm.getPassword();
} }
public void testCreateLoadBalancerRule() throws Exception { public void testCreateLoadBalancerRule() throws Exception {
rule = client.getLoadBalancerClient().createLoadBalancerRuleForPublicIP(ip.getId(), Algorithm.LEASTCONN, prefix, while (rule == null) {
22, 22); 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; assert (rule.getPublicIPId() == ip.getId()) : rule;
assertEquals(rule.getPublicPort(), 22); assertEquals(rule.getPublicPort(), 22);
assertEquals(rule.getPrivatePort(), 22); assertEquals(rule.getPrivatePort(), 22);
@ -84,18 +98,33 @@ public class LoadBalancerClientLiveTest extends BaseCloudStackClientLiveTest {
vm.getId())); vm.getId()));
assertEquals(client.getLoadBalancerClient().listVirtualMachinesAssignedToLoadBalancerRule(rule.getId()).size(), 1); assertEquals(client.getLoadBalancerClient().listVirtualMachinesAssignedToLoadBalancerRule(rule.getId()).size(), 1);
assert loadBalancerRuleActive.apply(rule) : rule; assert loadBalancerRuleActive.apply(rule) : rule;
IPSocket socket = new IPSocket(ip.getIPAddress(), 22); loopAndCheckSSH();
assert socketTester.apply(socket) : vm;
} }
@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 { public void testRemoveFromLoadBalancerRule() throws Exception {
assert jobComplete.apply(client.getLoadBalancerClient().removeVirtualMachinesFromLoadBalancerRule(rule.getId(), assert jobComplete.apply(client.getLoadBalancerClient().removeVirtualMachinesFromLoadBalancerRule(rule.getId(),
vm.getId())); vm.getId()));
assertEquals(client.getLoadBalancerClient().listVirtualMachinesAssignedToLoadBalancerRule(rule.getId()).size(), 0); assertEquals(client.getLoadBalancerClient().listVirtualMachinesAssignedToLoadBalancerRule(rule.getId()).size(), 0);
assertEquals(rule.getState(), State.ADD); assertEquals(rule.getState(), State.ADD);
IPSocket socket = new IPSocket(ip.getIPAddress(), 22); checkSSH(new IPSocket(ip.getIPAddress(), 22));
assert !socketTester.apply(socket);
} }
@AfterGroups(groups = "live") @AfterGroups(groups = "live")
@ -116,7 +145,7 @@ public class LoadBalancerClientLiveTest extends BaseCloudStackClientLiveTest {
Set<LoadBalancerRule> response = client.getLoadBalancerClient().listLoadBalancerRules(); Set<LoadBalancerRule> response = client.getLoadBalancerClient().listLoadBalancerRules();
assert null != response; assert null != response;
assertTrue(response.size() >= 0); assertTrue(response.size() >= 0);
for (final LoadBalancerRule rule : response) { for (LoadBalancerRule rule : response) {
LoadBalancerRule newDetails = findRuleWithId(rule.getId()); LoadBalancerRule newDetails = findRuleWithId(rule.getId());
assertEquals(rule.getId(), newDetails.getId()); assertEquals(rule.getId(), newDetails.getId());
checkRule(rule); checkRule(rule);

View File

@ -19,6 +19,7 @@
package org.jclouds.cloudstack.features; package org.jclouds.cloudstack.features;
import static com.google.common.collect.Iterables.find;
import static com.google.common.collect.Iterables.getOnlyElement; import static com.google.common.collect.Iterables.getOnlyElement;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue; 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.AsyncCreateResponse;
import org.jclouds.cloudstack.domain.IPForwardingRule; import org.jclouds.cloudstack.domain.IPForwardingRule;
import org.jclouds.cloudstack.domain.Network;
import org.jclouds.cloudstack.domain.PublicIPAddress; import org.jclouds.cloudstack.domain.PublicIPAddress;
import org.jclouds.cloudstack.domain.VirtualMachine; import org.jclouds.cloudstack.domain.VirtualMachine;
import org.jclouds.cloudstack.options.ListIPForwardingRulesOptions; import org.jclouds.cloudstack.options.ListIPForwardingRulesOptions;
import org.jclouds.cloudstack.predicates.NetworkPredicates;
import org.jclouds.compute.domain.ExecResponse; import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.net.IPSocket; import org.jclouds.net.IPSocket;
@ -48,23 +51,34 @@ public class NATClientLiveTest extends BaseCloudStackClientLiveTest {
private PublicIPAddress ip = null; private PublicIPAddress ip = null;
private VirtualMachine vm; private VirtualMachine vm;
private IPForwardingRule rule; private IPForwardingRule rule;
private Network network;
@BeforeGroups(groups = "live") @BeforeGroups(groups = "live")
public void setupClient() { public void setupClient() {
super.setupClient(); super.setupClient();
prefix += "nat"; prefix += "nat";
ip = AddressClientLiveTest.createPublicIPAddress(client, jobComplete); network = find(client.getNetworkClient().listNetworks(), NetworkPredicates.supportsStaticNAT());
vm = VirtualMachineClientLiveTest.createVirtualMachine(client, jobComplete, virtualMachineRunning); vm = VirtualMachineClientLiveTest.createVirtualMachineInNetwork(network, client, jobComplete,
virtualMachineRunning);
if (vm.getPassword() != null) if (vm.getPassword() != null)
password = vm.getPassword(); password = vm.getPassword();
} }
public void testCreateIPForwardingRule() throws Exception { public void testCreateIPForwardingRule() throws Exception {
for (ip = reuseOrAssociate.apply(network); (!ip.isStaticNAT() || ip.getVirtualMachineId() != vm.getId()); ip = reuseOrAssociate
assert !ip.isStaticNAT(); .apply(network)) {
client.getNATClient().enableStaticNATForVirtualMachine(vm.getId(), ip.getId()); // check to see if someone already grabbed this ip
ip = client.getAddressClient().getPublicIPAddress(ip.getId()); if (ip.getVirtualMachineId() > 0 && ip.getVirtualMachineId() != vm.getId())
assert ip.isStaticNAT(); 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); AsyncCreateResponse job = client.getNATClient().createIPForwardingRule(ip.getId(), "tcp", 22);
assert jobComplete.apply(job.getJobId()); assert jobComplete.apply(job.getJobId());
@ -76,7 +90,7 @@ public class NATClientLiveTest extends BaseCloudStackClientLiveTest {
checkRule(rule); checkRule(rule);
IPSocket socket = new IPSocket(ip.getIPAddress(), 22); IPSocket socket = new IPSocket(ip.getIPAddress(), 22);
socketTester.apply(socket); socketTester.apply(socket);
SshClient client = sshFactory.create(socket, new Credentials("root",password)); SshClient client = sshFactory.create(socket, new Credentials("root", password));
try { try {
client.connect(); client.connect();
ExecResponse exec = client.exec("echo hello"); ExecResponse exec = client.exec("echo hello");
@ -92,22 +106,24 @@ public class NATClientLiveTest extends BaseCloudStackClientLiveTest {
if (rule != null) { if (rule != null) {
client.getNATClient().deleteIPForwardingRule(rule.getId()); client.getNATClient().deleteIPForwardingRule(rule.getId());
} }
if (vm != null) {
jobComplete.apply(client.getVirtualMachineClient().destroyVirtualMachine(vm.getId()));
}
if (ip != null) { if (ip != null) {
client.getAddressClient().disassociateIPAddress(ip.getId()); client.getAddressClient().disassociateIPAddress(ip.getId());
} }
if (vm != null) {
assert jobComplete.apply(client.getVirtualMachineClient().destroyVirtualMachine(vm.getId()));
}
super.tearDown(); super.tearDown();
} }
@Test(enabled = false)
// takes too long
public void testListIPForwardingRules() throws Exception { public void testListIPForwardingRules() throws Exception {
Set<IPForwardingRule> response = client.getNATClient().listIPForwardingRules(); Set<IPForwardingRule> response = client.getNATClient().listIPForwardingRules();
assert null != response; assert null != response;
assertTrue(response.size() >= 0); assertTrue(response.size() >= 0);
for (IPForwardingRule rule : response) { for (IPForwardingRule rule : response) {
IPForwardingRule newDetails = getOnlyElement(client.getNATClient().listIPForwardingRules( IPForwardingRule newDetails = getOnlyElement(client.getNATClient().listIPForwardingRules(
ListIPForwardingRulesOptions.Builder.id(rule.getId()))); ListIPForwardingRulesOptions.Builder.id(rule.getId())));
assertEquals(rule.getId(), newDetails.getId()); assertEquals(rule.getId(), newDetails.getId());
checkRule(rule); checkRule(rule);
} }

View File

@ -30,9 +30,11 @@ import static org.testng.Assert.assertTrue;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutionException;
import org.jclouds.cloudstack.CloudStackClient; import org.jclouds.cloudstack.CloudStackClient;
import org.jclouds.cloudstack.domain.AsyncCreateResponse; import org.jclouds.cloudstack.domain.AsyncCreateResponse;
import org.jclouds.cloudstack.domain.AsyncJob;
import org.jclouds.cloudstack.domain.GuestIPType; import org.jclouds.cloudstack.domain.GuestIPType;
import org.jclouds.cloudstack.domain.NIC; import org.jclouds.cloudstack.domain.NIC;
import org.jclouds.cloudstack.domain.Network; import org.jclouds.cloudstack.domain.Network;
@ -49,6 +51,7 @@ import org.testng.annotations.AfterGroups;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Throwables;
import com.google.common.collect.ComparisonChain; import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Ordering; import com.google.common.collect.Ordering;
@ -140,7 +143,13 @@ public class VirtualMachineClientLiveTest extends BaseCloudStackClientLiveTest {
AsyncCreateResponse job = client.getVirtualMachineClient().deployVirtualMachine(serviceOfferingId, templateId, AsyncCreateResponse job = client.getVirtualMachineClient().deployVirtualMachine(serviceOfferingId, templateId,
zoneId, options); zoneId, options);
assert jobComplete.apply(job.getJobId()); assert jobComplete.apply(job.getJobId());
VirtualMachine vm = client.getAsyncJobClient().<VirtualMachine> getAsyncJob(job.getJobId()).getResult(); AsyncJob<VirtualMachine> jobWithResult = client.getAsyncJobClient().<VirtualMachine> 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()) { if (vm.isPasswordEnabled()) {
assert vm.getPassword() != null : vm; assert vm.getPassword() != null : vm;
} }

View File

@ -0,0 +1,154 @@
/**
*
* Copyright (C) 2010 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.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<Long> 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.<PublicIPAddress> 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<Long> 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.<PublicIPAddress> 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<Long> 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.<PublicIPAddress> 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);
}
}

View File

@ -0,0 +1,88 @@
/**
*
* Copyright (C) 2010 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.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.<String, String> 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.<String, String> 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
.<String, String> 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.<String, String> of("StaticNat", "true",
"PortForwarding", "true")))).build();
assert Predicates.and(supportsPortForwarding(), supportsStaticNAT()).apply(network);
assert !hasLoadBalancerService().apply(network);
}
}

View File

@ -0,0 +1,71 @@
/**
*
* Copyright (C) 2010 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.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);
}
}

View File

@ -146,7 +146,7 @@
</category> </category>
<category name="jclouds.ssh"> <category name="jclouds.ssh">
<priority value="DEBUG" /> <priority value="TRACE" />
<appender-ref ref="ASYNCSSH" /> <appender-ref ref="ASYNCSSH" />
</category> </category>