added cloudstack support to launch servers in a network with ip forwarding

This commit is contained in:
Adrian Cole 2011-11-14 19:23:41 +02:00
parent 4329129c25
commit be7cf42f04
28 changed files with 899 additions and 201 deletions

View File

@ -34,6 +34,8 @@ public class CloudStackPropertiesBuilder extends PropertiesBuilder {
protected Properties defaultProperties() {
Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_API_VERSION, "2.2");
properties.setProperty("jclouds.ssh.max-retries", "7");
properties.setProperty("jclouds.ssh.retry-auth", "true");
return properties;
}

View File

@ -18,11 +18,13 @@
*/
package org.jclouds.cloudstack.compute.config;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
@ -35,13 +37,19 @@ import org.jclouds.cloudstack.compute.functions.VirtualMachineToNodeMetadata;
import org.jclouds.cloudstack.compute.functions.ZoneToLocation;
import org.jclouds.cloudstack.compute.options.CloudStackTemplateOptions;
import org.jclouds.cloudstack.compute.strategy.CloudStackComputeServiceAdapter;
import org.jclouds.cloudstack.domain.IPForwardingRule;
import org.jclouds.cloudstack.domain.Network;
import org.jclouds.cloudstack.domain.OSType;
import org.jclouds.cloudstack.domain.ServiceOffering;
import org.jclouds.cloudstack.domain.Template;
import org.jclouds.cloudstack.domain.User;
import org.jclouds.cloudstack.domain.VirtualMachine;
import org.jclouds.cloudstack.domain.Zone;
import org.jclouds.cloudstack.features.GuestOSClient;
import org.jclouds.cloudstack.functions.StaticNATVirtualMachineInNetwork;
import org.jclouds.cloudstack.predicates.JobComplete;
import org.jclouds.cloudstack.suppliers.GetCurrentUser;
import org.jclouds.cloudstack.suppliers.NetworksForCurrentUser;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.config.ComputeServiceAdapterContextModule;
@ -51,14 +59,19 @@ import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.domain.Location;
import org.jclouds.location.suppliers.OnlyLocationOrFirstZone;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.Maps;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.FactoryModuleBuilder;
/**
*
@ -90,6 +103,9 @@ public class CloudStackComputeServiceContextModule
bind(TemplateOptions.class).to(CloudStackTemplateOptions.class);
bind(new TypeLiteral<Function<Template, OperatingSystem>>() {
}).to(TemplateToOperatingSystem.class);
install(new FactoryModuleBuilder().build(StaticNATVirtualMachineInNetwork.Factory.class));
bind(new TypeLiteral<CacheLoader<Long, IPForwardingRule>>() {
}).to(GetIPForwardingRuleByVirtualMachine.class);
}
@Provides
@ -128,10 +144,58 @@ public class CloudStackComputeServiceContextModule
});
}
@Provides
@Singleton
@Memoized
public Supplier<Map<Long, Network>> listNetworks(@Named(PROPERTY_SESSION_INTERVAL) long seconds,
final NetworksForCurrentUser networksForCurrentUser) {
return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<Long, Network>>(authException,
seconds, networksForCurrentUser);
}
@Provides
@Singleton
@Memoized
public Supplier<User> getCurrentUser(@Named(PROPERTY_SESSION_INTERVAL) long seconds,
final GetCurrentUser getCurrentUser) {
return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<User>(authException, seconds,
getCurrentUser);
}
@Provides
@Singleton
protected Predicate<Long> jobComplete(JobComplete jobComplete) {
// TODO: parameterize
return new RetryablePredicate<Long>(jobComplete, 1200, 1, 5, TimeUnit.SECONDS);
}
@Provides
@Singleton
protected Cache<Long, IPForwardingRule> getIPForwardingRuleByVirtualMachine(
CacheLoader<Long, IPForwardingRule> getIPForwardingRule) {
return CacheBuilder.newBuilder().build(getIPForwardingRule);
}
@Singleton
public static class GetIPForwardingRuleByVirtualMachine extends CacheLoader<Long, IPForwardingRule> {
private final CloudStackClient client;
@Inject
public GetIPForwardingRuleByVirtualMachine(CloudStackClient client) {
this.client = checkNotNull(client, "client");
}
/**
* @throws ResourceNotFoundException
* when there is no ip forwarding rule available for the VM
*/
@Override
public IPForwardingRule load(Long input) {
IPForwardingRule rule = client.getNATClient().getIPForwardingRuleForVirtualMachine(input);
if (rule == null)
throw new ResourceNotFoundException("no ip forwarding rule for: " + input);
return rule;
}
}
}

View File

@ -27,6 +27,7 @@ import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.cloudstack.domain.IPForwardingRule;
import org.jclouds.cloudstack.domain.VirtualMachine;
import org.jclouds.collect.FindResourceInSet;
import org.jclouds.collect.Memoized;
@ -37,12 +38,17 @@ import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.util.InetAddresses2;
import org.jclouds.util.Throwables2;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.base.Throwables;
import com.google.common.cache.Cache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.UncheckedExecutionException;
/**
* @author Adrian Cole
@ -66,16 +72,20 @@ public class VirtualMachineToNodeMetadata implements Function<VirtualMachine, No
private final FindLocationForVirtualMachine findLocationForVirtualMachine;
private final FindHardwareForVirtualMachine findHardwareForVirtualMachine;
private final FindImageForVirtualMachine findImageForVirtualMachine;
private final Cache<Long, IPForwardingRule> getIPForwardingRuleByVirtualMachine;
@Inject
VirtualMachineToNodeMetadata(Map<String, Credentials> credentialStore,
FindLocationForVirtualMachine findLocationForVirtualMachine,
FindHardwareForVirtualMachine findHardwareForVirtualMachine,
FindImageForVirtualMachine findImageForVirtualMachine) {
FindImageForVirtualMachine findImageForVirtualMachine,
Cache<Long, IPForwardingRule> getIPForwardingRuleByVirtualMachine) {
this.credentialStore = checkNotNull(credentialStore, "credentialStore");
this.findLocationForVirtualMachine = checkNotNull(findLocationForVirtualMachine, "findLocationForVirtualMachine");
this.findHardwareForVirtualMachine = checkNotNull(findHardwareForVirtualMachine, "findHardwareForVirtualMachine");
this.findImageForVirtualMachine = checkNotNull(findImageForVirtualMachine, "findImageForVirtualMachine");
this.getIPForwardingRuleByVirtualMachine = checkNotNull(getIPForwardingRuleByVirtualMachine,
"getIPForwardingRuleByVirtualMachine");
}
@Override
@ -108,6 +118,15 @@ public class VirtualMachineToNodeMetadata implements Function<VirtualMachine, No
else
builder.publicAddresses(addresses);
}
try {
IPForwardingRule rule = getIPForwardingRuleByVirtualMachine.getUnchecked(from.getId());
builder.publicAddresses(ImmutableSet.<String> of(rule.getIPAddress()));
} catch (UncheckedExecutionException e) {
if (Throwables2.getFirstThrowableOfType(e, ResourceNotFoundException.class) == null) {
Throwables.propagateIfPossible(e.getCause());
throw e;
}
}
builder.credentials(credentialStore.get("node#" + from.getId()));
return builder.build();
}

View File

@ -55,6 +55,7 @@ import com.google.common.collect.Sets;
public class CloudStackTemplateOptions extends TemplateOptions implements Cloneable {
protected Set<Long> securityGroupIds = Sets.<Long> newLinkedHashSet();
protected Set<Long> networkIds = Sets.<Long> newLinkedHashSet();
protected String keyPair;
@Override
@ -70,6 +71,7 @@ public class CloudStackTemplateOptions extends TemplateOptions implements Clonea
if (to instanceof CloudStackTemplateOptions) {
CloudStackTemplateOptions eTo = CloudStackTemplateOptions.class.cast(to);
eTo.securityGroupIds(this.securityGroupIds);
eTo.keyPair(this.keyPair);
}
}
@ -93,6 +95,26 @@ public class CloudStackTemplateOptions extends TemplateOptions implements Clonea
return securityGroupIds;
}
/**
* @see DeployVirtualMachineOptions#networkId
*/
public CloudStackTemplateOptions networkId(long networkId) {
this.networkIds.add(networkId);
return this;
}
/**
* @see DeployVirtualMachineOptions#networkIds
*/
public CloudStackTemplateOptions networkIds(Iterable<Long> networkIds) {
Iterables.addAll(this.networkIds, checkNotNull(networkIds, "networkIds was null"));
return this;
}
public Set<Long> getNetworkIds() {
return networkIds;
}
/**
* @see DeployVirtualMachineOptions#keyPair(String)
*/
@ -125,6 +147,22 @@ public class CloudStackTemplateOptions extends TemplateOptions implements Clonea
return options.securityGroupIds(securityGroupIds);
}
/**
* @see CloudStackTemplateOptions#networkId
*/
public static CloudStackTemplateOptions networkId(long id) {
CloudStackTemplateOptions options = new CloudStackTemplateOptions();
return options.networkId(id);
}
/**
* @see CloudStackTemplateOptions#networkIds
*/
public static CloudStackTemplateOptions networkIds(Iterable<Long> networkIds) {
CloudStackTemplateOptions options = new CloudStackTemplateOptions();
return options.networkIds(networkIds);
}
/**
* @see CloudStackTemplateOptions#keyPair
*/

View File

@ -20,7 +20,9 @@ package org.jclouds.cloudstack.compute.strategy;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Throwables.propagate;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.getOnlyElement;
import java.util.Map;
import java.util.concurrent.ExecutionException;
@ -30,17 +32,21 @@ import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import com.google.common.base.Predicates;
import org.jclouds.cloudstack.CloudStackClient;
import org.jclouds.cloudstack.compute.options.CloudStackTemplateOptions;
import org.jclouds.cloudstack.domain.AsyncCreateResponse;
import org.jclouds.cloudstack.domain.AsyncJob;
import org.jclouds.cloudstack.domain.Network;
import org.jclouds.cloudstack.domain.PublicIPAddress;
import org.jclouds.cloudstack.domain.ServiceOffering;
import org.jclouds.cloudstack.domain.Template;
import org.jclouds.cloudstack.domain.VirtualMachine;
import org.jclouds.cloudstack.domain.Zone;
import org.jclouds.cloudstack.functions.StaticNATVirtualMachineInNetwork;
import org.jclouds.cloudstack.functions.StaticNATVirtualMachineInNetwork.Factory;
import org.jclouds.cloudstack.options.DeployVirtualMachineOptions;
import org.jclouds.cloudstack.predicates.TemplatePredicates;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.reference.ComputeServiceConstants;
@ -48,7 +54,7 @@ import org.jclouds.domain.Credentials;
import org.jclouds.logging.Logger;
import com.google.common.base.Predicate;
import com.google.common.base.Throwables;
import com.google.common.base.Supplier;
/**
* defines the connection between the {@link CloudStackClient} implementation
@ -65,63 +71,96 @@ public class CloudStackComputeServiceAdapter implements
private final CloudStackClient client;
private final Predicate<Long> jobComplete;
private final Supplier<Map<Long, Network>> networkSupplier;
private final Factory staticNATVMInNetwork;
private final Map<String, Credentials> credentialStore;
@Inject
public CloudStackComputeServiceAdapter(CloudStackClient client, Predicate<Long> jobComplete) {
public CloudStackComputeServiceAdapter(CloudStackClient client, Predicate<Long> jobComplete,
@Memoized Supplier<Map<Long, Network>> networkSupplier,
StaticNATVirtualMachineInNetwork.Factory staticNATVMInNetwork, Map<String, Credentials> credentialStore) {
this.client = checkNotNull(client, "client");
this.jobComplete=checkNotNull(jobComplete, "jobComplete");
this.jobComplete = checkNotNull(jobComplete, "jobComplete");
this.networkSupplier = checkNotNull(networkSupplier, "networkSupplier");
this.staticNATVMInNetwork = checkNotNull(staticNATVMInNetwork, "staticNATVMInNetwork");
this.credentialStore = checkNotNull(credentialStore, "credentialStore");
}
@Override
public VirtualMachine createNodeWithGroupEncodedIntoNameThenStoreCredentials(String group, String name,
org.jclouds.compute.domain.Template template, Map<String, Credentials> credentialStore) {
public NodeAndInitialCredentials<VirtualMachine> createNodeWithGroupEncodedIntoName(String group, String name,
org.jclouds.compute.domain.Template template) {
checkNotNull(template, "template was null");
checkNotNull(template.getOptions(), "template options was null");
checkArgument(template.getOptions().getClass().isAssignableFrom(CloudStackTemplateOptions.class),
"options class %s should have been assignable from CloudStackTemplateOptions", template.getOptions()
.getClass());
Map<Long, Network> networks = networkSupplier.get();
final long zoneId = Long.parseLong(template.getLocation().getId());
CloudStackTemplateOptions templateOptions = template.getOptions().as(CloudStackTemplateOptions.class);
DeployVirtualMachineOptions options = new DeployVirtualMachineOptions();
if (templateOptions.getSecurityGroupIds().size() > 0)
if (templateOptions.getSecurityGroupIds().size() > 0) {
options.securityGroupIds(templateOptions.getSecurityGroupIds());
} else if (templateOptions.getNetworkIds().size() > 0) {
options.networkIds(templateOptions.getNetworkIds());
} else if (networks.size() > 0) {
try {
options.networkId(getOnlyElement(filter(networks.values(), new Predicate<Network>() {
@Override
public boolean apply(Network arg0) {
return arg0.getZoneId() == zoneId;
}
})).getId());
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("please choose a specific network in zone " + zoneId + ": " + networks);
}
} else {
throw new IllegalArgumentException("please setup a network or security group for zone: " + zoneId);
}
if (templateOptions.getKeyPair() != null) {
options.keyPair(templateOptions.getKeyPair());
if (templateOptions.getRunScript() != null) {
checkArgument(
credentialStore.containsKey("keypair#" + templateOptions.getKeyPair()),
"no private key configured for: %s; please use options.overrideLoginCredentialWith(rsa_private_text)",
templateOptions.getKeyPair());
checkArgument(
credentialStore.containsKey("keypair#" + templateOptions.getKeyPair()),
"no private key configured for: %s; please use options.overrideLoginCredentialWith(rsa_private_text)",
templateOptions.getKeyPair());
}
}
long zoneId = Long.parseLong(template.getLocation().getId());
long templateId = Long.parseLong(template.getImage().getId());
long serviceOfferingId = Long.parseLong(template.getHardware().getId());
System.out.printf("serviceOfferingId %d, templateId %d, zoneId %d, options %s%n", serviceOfferingId, templateId,
logger.info("serviceOfferingId %d, templateId %d, zoneId %d, options %s%n", serviceOfferingId, templateId,
zoneId, options);
AsyncCreateResponse job = client.getVirtualMachineClient().deployVirtualMachineInZone(zoneId, serviceOfferingId,
templateId, options);
assert jobComplete.apply(job.getJobId());
boolean completed = jobComplete.apply(job.getJobId());
AsyncJob<VirtualMachine> jobWithResult = client.getAsyncJobClient().<VirtualMachine> getAsyncJob(job.getJobId());
assert completed : jobWithResult;
if (jobWithResult.getError() != null)
Throwables.propagate(new ExecutionException(String.format("job %s failed with exception %s", job.getId(),
jobWithResult.getError().toString())) {
propagate(new ExecutionException(String.format("job %s failed with exception %s", job.getId(), jobWithResult
.getError().toString())) {
private static final long serialVersionUID = 4371112085613620239L;
});
VirtualMachine vm = jobWithResult.getResult();
Credentials credentials = null;
if (vm.isPasswordEnabled()) {
assert vm.getPassword() != null : vm;
Credentials credentials = new Credentials("root", vm.getPassword());
credentialStore.put("node#" + vm.getId(), credentials);
credentials = new Credentials(null, vm.getPassword());
} else {
// assert templateOptions.getKeyPair() != null : vm;
Credentials credentials = credentialStore.get("keypair#" + templateOptions.getKeyPair());
credentialStore.put("node#" + vm.getId(), credentials);
credentials = credentialStore.get("keypair#" + templateOptions.getKeyPair());
}
return vm;
// TODO: possibly not all network ids, do we want to do this
for (long networkId : options.getNetworkIds()) {
// TODO: log this
PublicIPAddress ip = staticNATVMInNetwork.create(networks.get(networkId)).apply(vm);
}
return new NodeAndInitialCredentials<VirtualMachine>(vm, vm.getId() + "", credentials);
}
@Override

View File

@ -56,4 +56,34 @@ public class AsyncCreateResponse {
return jobId;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (id ^ (id >>> 32));
result = prime * result + (int) (jobId ^ (jobId >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AsyncCreateResponse other = (AsyncCreateResponse) obj;
if (id != other.id)
return false;
if (jobId != other.jobId)
return false;
return true;
}
@Override
public String toString() {
return "[id=" + id + ", jobId=" + jobId + "]";
}
}

View File

@ -32,7 +32,7 @@ import org.jclouds.concurrent.Timeout;
* @see <a href="http://download.cloud.com/releases/2.2.0/api_2.2.12/TOC_User.html" />
* @author Adrian Cole
*/
@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
@Timeout(duration = 120, timeUnit = TimeUnit.SECONDS)
public interface AccountClient {
/**
* Lists Accounts

View File

@ -46,7 +46,9 @@ import com.google.common.util.concurrent.ListenableFuture;
* <p/>
*
* @see NATClient
* @see <a href="http://download.cloud.com/releases/2.2.0/api_2.2.12/TOC_User.html" />
* @see <a
* href="http://download.cloud.com/releases/2.2.0/api_2.2.12/TOC_User.html"
* />
* @author Adrian Cole
*/
@RequestFilters(QuerySigner.class)
@ -74,6 +76,28 @@ public interface NATAsyncClient {
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<IPForwardingRule> getIPForwardingRule(@QueryParam("id") long id);
/**
* @see NATClient#getIPForwardingRuleForIPAddress
*/
@GET
@QueryParams(keys = "command", values = "listIpForwardingRules")
@SelectJson("ipforwardingrule")
@OnlyElement
@Consumes(MediaType.APPLICATION_JSON)
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<IPForwardingRule> getIPForwardingRuleForIPAddress(@QueryParam("ipaddressid") long id);
/**
* @see NATClient#getIPForwardingRuleForVirtualMachine
*/
@GET
@QueryParams(keys = "command", values = "listIpForwardingRules")
@SelectJson("ipforwardingrule")
@OnlyElement
@Consumes(MediaType.APPLICATION_JSON)
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<IPForwardingRule> getIPForwardingRuleForVirtualMachine(@QueryParam("virtualmachineid") long id);
/**
* @see NATClient#createIPForwardingRule
*/

View File

@ -32,7 +32,9 @@ import org.jclouds.concurrent.Timeout;
* <p/>
*
* @see IPForwardingRuleAsyncClient
* @see <a href="http://download.cloud.com/releases/2.2.0/api_2.2.12/TOC_User.html" />
* @see <a
* href="http://download.cloud.com/releases/2.2.0/api_2.2.12/TOC_User.html"
* />
* @author Adrian Cole
*/
@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
@ -56,6 +58,24 @@ public interface NATClient {
*/
IPForwardingRule getIPForwardingRule(long id);
/**
* get a specific IPForwardingRule by ipaddress id
*
* @param id
* IPAddress of rule to get
* @return IPForwardingRule or null if not found
*/
IPForwardingRule getIPForwardingRuleForIPAddress(long id);
/**
* get a specific IPForwardingRule by virtual machine id
*
* @param id
* virtual machine of rule to get
* @return IPForwardingRule or null if not found
*/
IPForwardingRule getIPForwardingRuleForVirtualMachine(long id);
/**
* Creates an ip forwarding rule
*

View File

@ -50,16 +50,18 @@ import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.annotations.Unwrap;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
import com.google.common.util.concurrent.ListenableFuture;
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
/**
* Provides asynchronous access to cloudstack via their REST API.
* <p/>
*
* @see TemplateClient
* @see <a href="http://download.cloud.com/releases/2.2.0/api_2.2.12/TOC_User.html" />
* @see <a
* href="http://download.cloud.com/releases/2.2.0/api_2.2.12/TOC_User.html"
* />
* @author Adrian Cole
*/
@RequestFilters(QuerySigner.class)
@ -74,7 +76,9 @@ public interface TemplateAsyncClient {
@QueryParams(keys = "command", values = "createTemplate")
@Unwrap
@Consumes(MediaType.APPLICATION_JSON)
ListenableFuture<AsyncCreateResponse> createTemplate(@BinderParam(BindTemplateMetadataToQueryParams.class) TemplateMetadata templateMetadata, CreateTemplateOptions... options);
ListenableFuture<AsyncCreateResponse> createTemplate(
@BinderParam(BindTemplateMetadataToQueryParams.class) TemplateMetadata templateMetadata,
CreateTemplateOptions... options);
/**
* @see TemplateClient#registerTemplate
@ -83,7 +87,10 @@ public interface TemplateAsyncClient {
@QueryParams(keys = "command", values = "registerTemplate")
@SelectJson("template")
@Consumes(MediaType.APPLICATION_JSON)
ListenableFuture<Template> registerTemplate(@BinderParam(BindTemplateMetadataToQueryParams.class) TemplateMetadata templateMetadata, @QueryParam("format") String format, @QueryParam("hypervisor") String hypervisor, @QueryParam("url") String url, @QueryParam("zoneid") long zoneId, RegisterTemplateOptions... options);
ListenableFuture<Template> registerTemplate(
@BinderParam(BindTemplateMetadataToQueryParams.class) TemplateMetadata templateMetadata,
@QueryParam("format") String format, @QueryParam("hypervisor") String hypervisor,
@QueryParam("url") String url, @QueryParam("zoneid") long zoneId, RegisterTemplateOptions... options);
/**
* @see TemplateClient#updateTemplate
@ -101,7 +108,8 @@ public interface TemplateAsyncClient {
@QueryParams(keys = "command", values = "copyTemplate")
@Unwrap
@Consumes(MediaType.APPLICATION_JSON)
ListenableFuture<AsyncCreateResponse> copyTemplateToZone(@QueryParam("id") long id, @QueryParam("sourcezoneid") long sourceZoneId, @QueryParam("destzoneid") long destZoneId);
ListenableFuture<AsyncCreateResponse> copyTemplateToZone(@QueryParam("id") long id,
@QueryParam("sourcezoneid") long sourceZoneId, @QueryParam("destzoneid") long destZoneId);
/**
* @see TemplateClient#deleteTemplate
@ -135,6 +143,7 @@ public interface TemplateAsyncClient {
* @see TemplateClient#getTemplate
*/
@GET
// templatefilter required in at least 2.2.8 version
@QueryParams(keys = { "command", "templatefilter" }, values = { "listTemplates", "executable" })
@SelectJson("template")
@OnlyElement
@ -147,7 +156,8 @@ public interface TemplateAsyncClient {
*/
@GET
@QueryParams(keys = "command", values = "updateTemplatePermissions")
ListenableFuture<Void> updateTemplatePermissions(@QueryParam("id") long id, UpdateTemplatePermissionsOptions... options);
ListenableFuture<Void> updateTemplatePermissions(@QueryParam("id") long id,
UpdateTemplatePermissionsOptions... options);
/**
* @see TemplateClient#listTemplatePermissions
@ -156,7 +166,8 @@ public interface TemplateAsyncClient {
@QueryParams(keys = "command", values = "listTemplatePermissions")
@Unwrap
@Consumes(MediaType.APPLICATION_JSON)
ListenableFuture<Set<TemplatePermission>> listTemplatePermissions(@QueryParam("id") long id, AccountInDomainOptions... options);
ListenableFuture<Set<TemplatePermission>> listTemplatePermissions(@QueryParam("id") long id,
AccountInDomainOptions... options);
/**
* @see TemplateClient#extractTemplate
@ -165,5 +176,6 @@ public interface TemplateAsyncClient {
@QueryParams(keys = "command", values = "extractTemplate")
@Unwrap
@Consumes(MediaType.APPLICATION_JSON)
ListenableFuture<AsyncCreateResponse> extractTemplate(@QueryParam("id") long id, @QueryParam("mode") ExtractMode mode, @QueryParam("zoneid") long zoneId, ExtractTemplateOptions... options);
ListenableFuture<AsyncCreateResponse> extractTemplate(@QueryParam("id") long id,
@QueryParam("mode") ExtractMode mode, @QueryParam("zoneid") long zoneId, ExtractTemplateOptions... options);
}

View File

@ -0,0 +1,92 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.cloudstack.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.cloudstack.CloudStackClient;
import org.jclouds.cloudstack.domain.AsyncCreateResponse;
import org.jclouds.cloudstack.domain.AsyncJob;
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 com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.cache.Cache;
import com.google.inject.assistedinject.Assisted;
/**
*
* @author Adrian Cole
*/
@Singleton
public class StaticNATVirtualMachineInNetwork implements Function<VirtualMachine, PublicIPAddress> {
public static interface Factory {
StaticNATVirtualMachineInNetwork create(Network in);
}
private final CloudStackClient client;
private final ReuseOrAssociateNewPublicIPAddress reuseOrAssociate;
private final Network network;
private final Predicate<Long> jobComplete;
private final Cache<Long, IPForwardingRule> getIPForwardingRuleByVirtualMachine;
@Inject
public StaticNATVirtualMachineInNetwork(CloudStackClient client,
ReuseOrAssociateNewPublicIPAddress reuseOrAssociate, Predicate<Long> jobComplete,
Cache<Long, IPForwardingRule> getIPForwardingRuleByVirtualMachine, @Assisted Network network) {
this.client = checkNotNull(client, "client");
this.reuseOrAssociate = checkNotNull(reuseOrAssociate, "reuseOrAssociate");
this.jobComplete = checkNotNull(jobComplete, "jobComplete");
this.getIPForwardingRuleByVirtualMachine = checkNotNull(getIPForwardingRuleByVirtualMachine,
"getIPForwardingRuleByVirtualMachine");
this.network = checkNotNull(network, "network");
}
public PublicIPAddress apply(VirtualMachine vm) {
PublicIPAddress ip;
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;
}
return ip;
}
AsyncCreateResponse job = client.getNATClient().createIPForwardingRule(ip.getId(), "tcp", 22);
checkState(jobComplete.apply(job.getJobId()), "Timeout creating IP forwarding rule: ", job);
AsyncJob<IPForwardingRule> response = client.getAsyncJobClient().getAsyncJob(job.getJobId());
checkState(response.getResult() != null, "No result after creating IP forwarding rule: ", response);
getIPForwardingRuleByVirtualMachine.asMap().put(vm.getId(), response.getResult());
return ip;
}
}

View File

@ -70,7 +70,12 @@ public class CloudStackErrorHandler implements HttpErrorHandler {
break;
case 409:
case 431:
exception = new IllegalStateException(message, exception);
if (command.getCurrentRequest().getRequestLine().indexOf("delete") != -1
&& message.indexOf("does not exist") != -1) {
exception = new ResourceNotFoundException(message, exception);
} else {
exception = new IllegalStateException(message, exception);
}
break;
}
} finally {

View File

@ -23,8 +23,11 @@ import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.encryption.internal.Base64;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
/**
* Options used to control what disk offerings are returned
@ -119,6 +122,23 @@ public class DeployVirtualMachineOptions extends AccountInDomainOptions {
return this;
}
public Iterable<Long> getNetworkIds() {
if (queryParameters.get("networkids").size() == 1) {
return Iterables.transform(
Splitter.on(",").split(Iterables.getOnlyElement(queryParameters.get("networkids"))),
new Function<String, Long>() {
@Override
public Long apply(String arg0) {
return Long.parseLong(arg0);
}
});
} else {
return ImmutableSet.<Long> of();
}
}
/**
* @param securityGroupId
* security group applied to the virtual machine. Should be passed

View File

@ -0,0 +1,69 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.cloudstack.suppliers;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.NoSuchElementException;
import javax.inject.Inject;
import org.jclouds.cloudstack.CloudStackClient;
import org.jclouds.cloudstack.domain.Account;
import org.jclouds.cloudstack.domain.User;
import org.jclouds.cloudstack.predicates.UserPredicates;
import org.jclouds.rest.annotations.Identity;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.Iterables;
/**
*
* @author Adrian Cole
*/
public class GetCurrentUser implements Supplier<User> {
private final CloudStackClient client;
private final String identity;
@Inject
public GetCurrentUser(CloudStackClient client, @Identity String identity) {
this.client = checkNotNull(client, "client");
this.identity = checkNotNull(identity, "identity");
}
@Override
public User get() {
Iterable<User> users = Iterables.concat(client.getAccountClient().listAccounts());
Predicate<User> apiKeyMatches = UserPredicates.apiKeyEquals(identity);
User currentUser = null;
try {
currentUser = Iterables.find(users, apiKeyMatches);
} catch (NoSuchElementException e) {
throw new NoSuchElementException(String.format("none of the following users match %s: %s", apiKeyMatches,
users));
}
if (currentUser.getAccountType() != Account.Type.USER)
throw new IllegalArgumentException(String.format(
"invalid account type: %s, please specify an apiKey of a USER, for example: %s",
currentUser.getAccountType(), Iterables.filter(users, UserPredicates.isUserAccount())));
return currentUser;
}
}

View File

@ -0,0 +1,66 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.cloudstack.suppliers;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.cloudstack.options.ListNetworksOptions.Builder.accountInDomain;
import java.util.Map;
import javax.inject.Inject;
import org.jclouds.cloudstack.CloudStackClient;
import org.jclouds.cloudstack.domain.Network;
import org.jclouds.cloudstack.domain.User;
import org.jclouds.cloudstack.features.NetworkClient;
import org.jclouds.collect.Memoized;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.collect.Maps;
/**
*
* @author Adrian Cole
*/
public class NetworksForCurrentUser implements Supplier<Map<Long, Network>> {
private final CloudStackClient client;
private final Supplier<User> currentUserSupplier;
@Inject
public NetworksForCurrentUser(CloudStackClient client, @Memoized Supplier<User> currentUserSupplier) {
this.client = checkNotNull(client, "client");
this.currentUserSupplier = checkNotNull(currentUserSupplier, "currentUserSupplier");
}
@Override
public Map<Long, Network> get() {
User currentUser = currentUserSupplier.get();
NetworkClient networkClient = client.getNetworkClient();
return Maps.uniqueIndex(
networkClient.listNetworks(accountInDomain(currentUser.getAccount(), currentUser.getDomainId())),
new Function<Network, Long>() {
@Override
public Long apply(Network arg0) {
return arg0.getId();
}
});
}
}

View File

@ -25,35 +25,47 @@ import static org.testng.Assert.fail;
import java.io.IOException;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import javax.inject.Singleton;
import org.jclouds.cloudstack.CloudStackClient;
import org.jclouds.cloudstack.CloudStackPropertiesBuilder;
import org.jclouds.cloudstack.compute.config.CloudStackComputeServiceContextModule.GetIPForwardingRuleByVirtualMachine;
import org.jclouds.cloudstack.compute.options.CloudStackTemplateOptions;
import org.jclouds.cloudstack.compute.strategy.CloudStackComputeServiceAdapter;
import org.jclouds.cloudstack.domain.IPForwardingRule;
import org.jclouds.cloudstack.domain.Network;
import org.jclouds.cloudstack.domain.ServiceOffering;
import org.jclouds.cloudstack.domain.SshKeyPair;
import org.jclouds.cloudstack.domain.User;
import org.jclouds.cloudstack.domain.VirtualMachine;
import org.jclouds.cloudstack.features.BaseCloudStackClientLiveTest;
import org.jclouds.cloudstack.functions.StaticNATVirtualMachineInNetwork;
import org.jclouds.cloudstack.predicates.JobComplete;
import org.jclouds.cloudstack.predicates.TemplatePredicates;
import org.jclouds.cloudstack.suppliers.GetCurrentUser;
import org.jclouds.cloudstack.suppliers.NetworksForCurrentUser;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials;
import org.jclouds.compute.ComputeTestUtils;
import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.functions.DefaultCredentialsFromImageOrOverridingCredentials;
import org.jclouds.compute.strategy.PrioritizeCredentialsFromTemplate;
import org.jclouds.domain.Credentials;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.net.IPSocket;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.rest.annotations.Identity;
import org.jclouds.ssh.SshClient;
import org.testng.annotations.AfterGroups;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.net.InetAddresses;
@ -61,15 +73,19 @@ import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Module;
import com.google.inject.Provides;
import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.FactoryModuleBuilder;
@Test(groups = "live", singleThreaded = true, testName = "CloudStackComputeServiceAdapterLiveTest")
public class CloudStackComputeServiceAdapterLiveTest extends BaseCloudStackClientLiveTest {
private CloudStackComputeServiceAdapter adapter;
private VirtualMachine vm;
private NodeAndInitialCredentials<VirtualMachine> vm;
private String keyPairName;
private Map<String, String> keyPair;
Map<String, Credentials> credentialStore = Maps.newLinkedHashMap();
@BeforeGroups(groups = { "live" })
public void setupClient() {
@ -78,8 +94,16 @@ public class CloudStackComputeServiceAdapterLiveTest extends BaseCloudStackClien
@Override
protected void configure() {
bindProperties(binder(), CloudStackComputeServiceAdapterLiveTest.this.setupProperties());
bindProperties(binder(), setupProperties());
bind(String.class).annotatedWith(Identity.class).toInstance(identity);
bind(new TypeLiteral<Supplier<User>>() {
}).annotatedWith(Memoized.class).to(GetCurrentUser.class).in(Scopes.SINGLETON);
bind(new TypeLiteral<Supplier<Map<Long, Network>>>() {
}).annotatedWith(Memoized.class).to(NetworksForCurrentUser.class).in(Scopes.SINGLETON);
bind(new TypeLiteral<Map<String, Credentials>>() {
}).toInstance(credentialStore);
bind(CloudStackClient.class).toInstance(context.getApi());
install(new FactoryModuleBuilder().build(StaticNATVirtualMachineInNetwork.Factory.class));
}
@SuppressWarnings("unused")
@ -88,6 +112,14 @@ public class CloudStackComputeServiceAdapterLiveTest extends BaseCloudStackClien
protected Predicate<Long> jobComplete(JobComplete jobComplete) {
return new RetryablePredicate<Long>(jobComplete, 1200, 1, 5, TimeUnit.SECONDS);
}
@SuppressWarnings("unused")
@Provides
@Singleton
protected Cache<Long, IPForwardingRule> getIPForwardingRuleByVirtualMachine(
GetIPForwardingRuleByVirtualMachine getIPForwardingRule) {
return CacheBuilder.newBuilder().build(getIPForwardingRule);
}
};
adapter = Guice.createInjector(module, new Log4JLoggingModule()).getInstance(
CloudStackComputeServiceAdapter.class);
@ -105,35 +137,47 @@ public class CloudStackComputeServiceAdapterLiveTest extends BaseCloudStackClien
assertFalse(Iterables.isEmpty(adapter.listLocations()));
}
private static final PrioritizeCredentialsFromTemplate prioritizeCredentialsFromTemplate = new PrioritizeCredentialsFromTemplate(
new DefaultCredentialsFromImageOrOverridingCredentials());
@Test
public void testCreateNodeWithGroupEncodedIntoNameThenStoreCredentialsWithSecurityGroup() {
public void testCreateNodeWithGroupEncodedIntoNameThenStoreCredentialsWithSecurityGroup()
throws InterruptedException {
String group = "foo";
String name = "node" + new Random().nextInt();
Template template = computeContext.getComputeService().templateBuilder().build();
client.getSSHKeyPairClient().deleteSSHKeyPair(keyPairName);
client.getSSHKeyPairClient().registerSSHKeyPair(keyPairName, keyPair.get("public"));
if (!client
.getTemplateClient()
.getTemplateInZone(Long.parseLong(template.getImage().getId()),
Long.parseLong(template.getLocation().getId())).isPasswordEnabled()) {
client.getSSHKeyPairClient().deleteSSHKeyPair(keyPairName);
client.getSSHKeyPairClient().registerSSHKeyPair(keyPairName, keyPair.get("public"));
Map<String, Credentials> credentialStore = Maps.newLinkedHashMap();
credentialStore.put("keypair#" + keyPairName, new Credentials("root", keyPair.get("private")));
credentialStore.put("keypair#" + keyPairName, new Credentials("root", keyPair.get("private")));
// TODO: look at SecurityGroupClientLiveTest for how to do this
template.getOptions().as(CloudStackTemplateOptions.class).keyPair(keyPairName);
vm = adapter.createNodeWithGroupEncodedIntoNameThenStoreCredentials(group, name, template, credentialStore);
// TODO: look at SecurityGroupClientLiveTest for how to do this
template.getOptions().as(CloudStackTemplateOptions.class).keyPair(keyPairName);
}
vm = adapter.createNodeWithGroupEncodedIntoName(group, name, template);
// TODO: check security groups vm.getSecurityGroups(),
// check other things, like cpu correct, mem correct, image/os is correct
// (as possible)
assert credentialStore.containsKey("node#" + vm.getId()) : "credentials to log into vm not found " + vm;
assert InetAddresses.isInetAddress(vm.getIPAddress()) : vm;
// check to see if we setup a NAT rule (conceding we could check this from
// cache)
IPForwardingRule rule = client.getNATClient().getIPForwardingRuleForVirtualMachine(vm.getNode().getId());
doConnectViaSsh(vm, credentialStore.get("node#" + vm.getId()));
String address = rule != null ? rule.getIPAddress() : vm.getNode().getIPAddress();
assert InetAddresses.isInetAddress(address) : vm;
IPSocket socket = new IPSocket(address, 22);
doConnectViaSsh(socket, prioritizeCredentialsFromTemplate.apply(template, vm.getCredentials()));
}
protected void doConnectViaSsh(VirtualMachine vm, Credentials creds) {
SshClient ssh = computeContext.utils().sshFactory().create(new IPSocket(vm.getIPAddress(), 22), creds);
protected void doConnectViaSsh(IPSocket socket, Credentials creds) {
SshClient ssh = computeContext.utils().sshFactory().create(socket, creds);
try {
ssh.connect();
ExecResponse hello = ssh.exec("echo hello");
@ -170,7 +214,7 @@ public class CloudStackComputeServiceAdapterLiveTest extends BaseCloudStackClien
@AfterGroups(groups = "live")
protected void tearDown() {
if (vm != null)
adapter.destroyNode(vm.getId() + "");
adapter.destroyNode(vm.getNodeId());
super.tearDown();
}
}

View File

@ -28,6 +28,7 @@ import org.jclouds.sshj.config.SshjSshClientModule;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Module;
/**
@ -49,8 +50,9 @@ public class CloudStackComputeServiceLiveTest extends BaseComputeServiceLiveTest
public void testAssignability() throws Exception {
@SuppressWarnings("unused")
RestContext<CloudStackClient, CloudStackAsyncClient> tmContext = new ComputeServiceContextFactory()
.createContext(provider, identity, credential).getProviderSpecificContext();
RestContext<CloudStackClient, CloudStackAsyncClient> tmContext = new ComputeServiceContextFactory(
setupRestProperties()).createContext(provider, identity, credential, ImmutableSet.<Module> of(),
setupProperties()).getProviderSpecificContext();
}
// cloudstack does not support metadata
@ -60,4 +62,3 @@ public class CloudStackComputeServiceLiveTest extends BaseComputeServiceLiveTest
"node userMetadata did not match %s %s", userMetadata, node);
}
}

View File

@ -27,6 +27,7 @@ import java.util.Set;
import org.jclouds.cloudstack.compute.functions.VirtualMachineToNodeMetadata.FindHardwareForVirtualMachine;
import org.jclouds.cloudstack.compute.functions.VirtualMachineToNodeMetadata.FindImageForVirtualMachine;
import org.jclouds.cloudstack.compute.functions.VirtualMachineToNodeMetadata.FindLocationForVirtualMachine;
import org.jclouds.cloudstack.domain.IPForwardingRule;
import org.jclouds.cloudstack.domain.VirtualMachine;
import org.jclouds.cloudstack.parse.ListVirtualMachinesResponseTest;
import org.jclouds.compute.domain.Hardware;
@ -36,10 +37,13 @@ import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.rest.ResourceNotFoundException;
import org.testng.annotations.Test;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
@ -50,6 +54,51 @@ import com.google.common.collect.Iterables;
@Test(groups = "unit", testName = "VirtualMachineToNodeMetadataTest")
public class VirtualMachineToNodeMetadataTest {
@Test
public void testApplyWhereVirtualMachineWithIPForwardingRule() throws UnknownHostException {
// note we are testing when no credentials are here. otherwise would be
// ("node#416696", new
// Credentials("root", "password"))
Map<String, Credentials> credentialStore = ImmutableMap.<String, Credentials> of();
Supplier<Set<? extends Location>> locationSupplier = Suppliers.<Set<? extends Location>> ofInstance(ImmutableSet
.<Location> of(ZoneToLocationTest.one, ZoneToLocationTest.two));
Supplier<Set<? extends Hardware>> hardwareSupplier = Suppliers.<Set<? extends Hardware>> ofInstance(ImmutableSet
.<Hardware> of(ServiceOfferingToHardwareTest.one, ServiceOfferingToHardwareTest.two));
Supplier<Set<? extends Image>> imageSupplier = Suppliers.<Set<? extends Image>> ofInstance(ImmutableSet
.<Image> of(TemplateToImageTest.one, TemplateToImageTest.two));
VirtualMachineToNodeMetadata parser = new VirtualMachineToNodeMetadata(credentialStore,
new FindLocationForVirtualMachine(locationSupplier), new FindHardwareForVirtualMachine(hardwareSupplier),
new FindImageForVirtualMachine(imageSupplier), CacheBuilder.newBuilder().<Long, IPForwardingRule> build(
new CacheLoader<Long, IPForwardingRule>() {
@Override
public IPForwardingRule load(Long arg0) throws Exception {
return IPForwardingRule.builder().id(1234l).IPAddress("1.1.1.1").build();
}
}));
// notice if we've already parsed this properly here, we can rely on it.
VirtualMachine guest = Iterables.get(new ListVirtualMachinesResponseTest().expected(), 0);
NodeMetadata node = parser.apply(guest);
assertEquals(
node.toString(),
new NodeMetadataBuilder().id("54").providerId("54").name("i-3-54-VM").location(ZoneToLocationTest.one)
.state(NodeState.PENDING).privateAddresses(ImmutableSet.of("10.1.1.18"))
.publicAddresses(ImmutableSet.of("1.1.1.1")).hardware(ServiceOfferingToHardwareTest.one)
.imageId(TemplateToImageTest.one.getId())
.operatingSystem(TemplateToImageTest.one.getOperatingSystem()).build().toString());
// because it wasn't present in the credential store.
assertEquals(node.getCredentials(), null);
}
@Test
public void testApplyWhereVirtualMachineWithNoPassword() throws UnknownHostException {
@ -66,10 +115,17 @@ public class VirtualMachineToNodeMetadataTest {
Supplier<Set<? extends Image>> imageSupplier = Suppliers.<Set<? extends Image>> ofInstance(ImmutableSet
.<Image> of(TemplateToImageTest.one, TemplateToImageTest.two));
VirtualMachineToNodeMetadata parser = new VirtualMachineToNodeMetadata(credentialStore,
new FindLocationForVirtualMachine(locationSupplier), new FindHardwareForVirtualMachine(hardwareSupplier),
new FindImageForVirtualMachine(imageSupplier));
new FindImageForVirtualMachine(imageSupplier), CacheBuilder.newBuilder().<Long, IPForwardingRule> build(
new CacheLoader<Long, IPForwardingRule>() {
@Override
public IPForwardingRule load(Long arg0) throws Exception {
throw new ResourceNotFoundException("no ip forwarding rule for: " + arg0);
}
}));
// notice if we've already parsed this properly here, we can rely on it.
VirtualMachine guest = Iterables.get(new ListVirtualMachinesResponseTest().expected(), 0);
@ -104,7 +160,15 @@ public class VirtualMachineToNodeMetadataTest {
VirtualMachineToNodeMetadata parser = new VirtualMachineToNodeMetadata(credentialStore,
new FindLocationForVirtualMachine(locationSupplier), new FindHardwareForVirtualMachine(hardwareSupplier),
new FindImageForVirtualMachine(imageSupplier));
new FindImageForVirtualMachine(imageSupplier), CacheBuilder.newBuilder().<Long, IPForwardingRule> build(
new CacheLoader<Long, IPForwardingRule>() {
@Override
public IPForwardingRule load(Long arg0) throws Exception {
throw new ResourceNotFoundException("no ip forwarding rule for: " + arg0);
}
}));
// notice if we've already parsed this properly here, we can rely on it.
VirtualMachine guest = Iterables.get(new ListVirtualMachinesResponseTest().expected(), 0);
@ -121,5 +185,4 @@ public class VirtualMachineToNodeMetadataTest {
assertEquals(node.getCredentials(), new Credentials("root", "password"));
}
}

View File

@ -19,6 +19,8 @@
package org.jclouds.cloudstack.compute.options;
import static org.jclouds.cloudstack.compute.options.CloudStackTemplateOptions.Builder.keyPair;
import static org.jclouds.cloudstack.compute.options.CloudStackTemplateOptions.Builder.networkId;
import static org.jclouds.cloudstack.compute.options.CloudStackTemplateOptions.Builder.networkIds;
import static org.jclouds.cloudstack.compute.options.CloudStackTemplateOptions.Builder.securityGroupId;
import static org.jclouds.cloudstack.compute.options.CloudStackTemplateOptions.Builder.securityGroupIds;
import static org.testng.Assert.assertEquals;
@ -74,6 +76,36 @@ public class CloudStackTemplateOptionsTest {
assertEquals(options.as(CloudStackTemplateOptions.class).getSecurityGroupIds(), ImmutableSet.of(3l));
}
@Test
public void testDefaultNetworkIds() {
TemplateOptions options = new CloudStackTemplateOptions();
assertEquals(options.as(CloudStackTemplateOptions.class).getNetworkIds(), ImmutableSet.of());
}
@Test
public void testNetworkId() {
TemplateOptions options = new CloudStackTemplateOptions().networkId(3l);
assertEquals(options.as(CloudStackTemplateOptions.class).getNetworkIds(), ImmutableSet.of(3l));
}
@Test
public void testNetworkIdStatic() {
TemplateOptions options = networkId(3l);
assertEquals(options.as(CloudStackTemplateOptions.class).getNetworkIds(), ImmutableSet.of(3l));
}
@Test
public void testNetworkIds() {
TemplateOptions options = new CloudStackTemplateOptions().networkIds(ImmutableSet.of(3l));
assertEquals(options.as(CloudStackTemplateOptions.class).getNetworkIds(), ImmutableSet.of(3l));
}
@Test
public void testNetworkIdsStatic() {
TemplateOptions options = networkIds(ImmutableSet.of(3l));
assertEquals(options.as(CloudStackTemplateOptions.class).getNetworkIds(), ImmutableSet.of(3l));
}
@Test
public void testKeyPair() {
TemplateOptions options = keyPair("test");

View File

@ -18,19 +18,27 @@
*/
package org.jclouds.cloudstack.features;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.get;
import static org.testng.Assert.assertEquals;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.jclouds.cloudstack.CloudStackAsyncClient;
import org.jclouds.cloudstack.CloudStackClient;
import org.jclouds.cloudstack.domain.Account;
import org.jclouds.cloudstack.domain.Template;
import org.jclouds.cloudstack.domain.User;
import org.jclouds.cloudstack.domain.VirtualMachine;
import org.jclouds.cloudstack.functions.ReuseOrAssociateNewPublicIPAddress;
import org.jclouds.cloudstack.options.ListTemplatesOptions;
import org.jclouds.cloudstack.predicates.CorrectHypervisorForZone;
import org.jclouds.cloudstack.predicates.JobComplete;
import org.jclouds.cloudstack.predicates.OSCategoryIn;
import org.jclouds.cloudstack.predicates.TemplatePredicates;
import org.jclouds.cloudstack.predicates.UserPredicates;
import org.jclouds.cloudstack.predicates.VirtualMachineDestroyed;
import org.jclouds.cloudstack.predicates.VirtualMachineRunning;
@ -50,6 +58,7 @@ import org.testng.annotations.AfterGroups;
import org.testng.annotations.BeforeGroups;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.inject.Guice;
@ -65,6 +74,33 @@ public class BaseCloudStackClientLiveTest extends BaseVersionedServiceLiveTest {
provider = "cloudstack";
}
public static long defaultTemplateOrPreferredInZone(Long defaultTemplate, CloudStackClient client, long zoneId) {
long templateId = defaultTemplate != null ? defaultTemplate : getTemplateForZone(client, zoneId);
return templateId;
}
public static long getTemplateForZone(CloudStackClient client, long zoneId) {
// TODO enum, as this is way too easy to mess up.
Set<String> acceptableCategories = ImmutableSet.of("Ubuntu", "CentOS");
final Predicate<Template> hypervisorPredicate = new CorrectHypervisorForZone(client).apply(zoneId);
final Predicate<Template> osTypePredicate = new OSCategoryIn(client).apply(acceptableCategories);
@SuppressWarnings("unchecked")
Predicate<Template> templatePredicate = Predicates.<Template> and(TemplatePredicates.isReady(),
hypervisorPredicate, osTypePredicate);
Iterable<Template> templates = filter(
client.getTemplateClient().listTemplates(ListTemplatesOptions.Builder.zoneId(zoneId)), templatePredicate);
if (Iterables.any(templates, TemplatePredicates.isPasswordEnabled())) {
templates = filter(templates, TemplatePredicates.isPasswordEnabled());
}
if (Iterables.size(templates) == 0) {
throw new NoSuchElementException(templatePredicate.toString());
}
long templateId = get(templates, 0).getId();
return templateId;
}
protected String prefix = System.getProperty("user.name");
protected CloudStackClient client;
@ -83,7 +119,6 @@ public class BaseCloudStackClientLiveTest extends BaseVersionedServiceLiveTest {
protected ComputeServiceContext computeContext;
protected void checkSSH(IPSocket socket) {
socketTester.apply(socket);
SshClient client = sshFactory.create(socket, new Credentials("root", password));
@ -97,7 +132,7 @@ public class BaseCloudStackClientLiveTest extends BaseVersionedServiceLiveTest {
client.disconnect();
}
}
@BeforeGroups(groups = "live")
public void setupClient() {
setupCredentials();

View File

@ -57,7 +57,9 @@ public class FirewallClientLiveTest extends BaseCloudStackClientLiveTest {
prefix += "rule";
try {
network = find(client.getNetworkClient().listNetworks(), NetworkPredicates.supportsPortForwarding());
vm = VirtualMachineClientLiveTest.createVirtualMachineInNetwork(network, client, jobComplete,
Long defaultTemplate = (imageId != null && !"".equals(imageId)) ? new Long(imageId) : null;
vm = VirtualMachineClientLiveTest.createVirtualMachineInNetwork(network,
defaultTemplateOrPreferredInZone(defaultTemplate, client, network.getZoneId()), client, jobComplete,
virtualMachineRunning);
if (vm.getPassword() != null)
password = vm.getPassword();

View File

@ -67,7 +67,9 @@ public class LoadBalancerClientLiveTest extends BaseCloudStackClientLiveTest {
prefix += "rule";
try {
network = find(client.getNetworkClient().listNetworks(), NetworkPredicates.hasLoadBalancerService());
vm = VirtualMachineClientLiveTest.createVirtualMachineInNetwork(network, client, jobComplete,
Long defaultTemplate = (imageId != null && !"".equals(imageId)) ? new Long(imageId) : null;
vm = VirtualMachineClientLiveTest.createVirtualMachineInNetwork(network,
defaultTemplateOrPreferredInZone(defaultTemplate, client, network.getZoneId()), client, jobComplete,
virtualMachineRunning);
if (vm.getPassword() != null)
password = vm.getPassword();

View File

@ -27,7 +27,6 @@ import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.ParseFirstJsonValueNamed;
import org.jclouds.http.functions.UnwrapOnlyJsonValue;
import org.jclouds.http.functions.UnwrapOnlyNestedJsonValue;
import org.jclouds.http.functions.UnwrapOnlyNestedJsonValueInSet;
import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;

View File

@ -18,27 +18,14 @@
*/
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;
import java.util.NoSuchElementException;
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;
import org.jclouds.ssh.SshClient;
import org.testng.annotations.AfterGroups;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
/**
@ -48,79 +35,6 @@ import org.testng.annotations.Test;
*/
@Test(groups = "live", singleThreaded = true, testName = "NATClientLiveTest")
public class NATClientLiveTest extends BaseCloudStackClientLiveTest {
private PublicIPAddress ip = null;
private VirtualMachine vm;
private IPForwardingRule rule;
private Network network;
private boolean networksDisabled;
@BeforeGroups(groups = "live")
public void setupClient() {
super.setupClient();
prefix += "nat";
try {
network = find(client.getNetworkClient().listNetworks(), NetworkPredicates.supportsStaticNAT());
vm = VirtualMachineClientLiveTest.createVirtualMachineInNetwork(network, client, jobComplete,
virtualMachineRunning);
if (vm.getPassword() != null)
password = vm.getPassword();
} catch (NoSuchElementException e) {
networksDisabled = true;
}
}
public void testCreateIPForwardingRule() throws Exception {
if (networksDisabled)
return;
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());
rule = client.getNATClient().getIPForwardingRule(job.getId());
assertEquals(rule.getIPAddressId(), ip.getId());
assertEquals(rule.getVirtualMachineId(), vm.getId());
assertEquals(rule.getStartPort(), 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();
}
}
@AfterGroups(groups = "live")
protected void tearDown() {
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());
}
super.tearDown();
}
@Test(enabled = false)
// takes too long

View File

@ -169,8 +169,10 @@ public class SecurityGroupClientLiveTest extends BaseCloudStackClientLiveTest {
public void testCreateVMInSecurityGroup() throws Exception {
if (!securityGroupsSupported)
return;
vm = VirtualMachineClientLiveTest.createVirtualMachineWithSecurityGroupInZone(zone.getId(), group.getId(),
client, jobComplete, virtualMachineRunning);
Long defaultTemplate = (imageId != null && !"".equals(imageId)) ? new Long(imageId) : null;
vm = VirtualMachineClientLiveTest.createVirtualMachineWithSecurityGroupInZone(zone.getId(),
defaultTemplateOrPreferredInZone(defaultTemplate, client, zone.getId()), group.getId(), client,
jobComplete, virtualMachineRunning);
if (vm.getPassword() != null)
password = vm.getPassword();
// ingress port 22

View File

@ -20,14 +20,12 @@ package org.jclouds.cloudstack.features;
import static com.google.common.base.Predicates.equalTo;
import static com.google.common.base.Predicates.or;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.find;
import static com.google.common.collect.Iterables.get;
import static com.google.common.collect.Iterables.getOnlyElement;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.ExecutionException;
@ -37,15 +35,10 @@ import org.jclouds.cloudstack.domain.AsyncJob;
import org.jclouds.cloudstack.domain.NIC;
import org.jclouds.cloudstack.domain.Network;
import org.jclouds.cloudstack.domain.ServiceOffering;
import org.jclouds.cloudstack.domain.Template;
import org.jclouds.cloudstack.domain.VirtualMachine;
import org.jclouds.cloudstack.domain.Zone;
import org.jclouds.cloudstack.options.DeployVirtualMachineOptions;
import org.jclouds.cloudstack.options.ListTemplatesOptions;
import org.jclouds.cloudstack.options.ListVirtualMachinesOptions;
import org.jclouds.cloudstack.predicates.CorrectHypervisorForZone;
import org.jclouds.cloudstack.predicates.OSCategoryIn;
import org.jclouds.cloudstack.predicates.TemplatePredicates;
import org.jclouds.net.IPSocket;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.util.InetAddresses2;
@ -53,11 +46,8 @@ import org.testng.annotations.AfterGroups;
import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Throwables;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Ordering;
import com.google.common.net.HostSpecifier;
@ -77,61 +67,50 @@ public class VirtualMachineClientLiveTest extends BaseCloudStackClientLiveTest {
}
};
public static VirtualMachine createVirtualMachine(CloudStackClient client, RetryablePredicate<Long> jobComplete,
RetryablePredicate<VirtualMachine> virtualMachineRunning) {
public static VirtualMachine createVirtualMachine(CloudStackClient client, Long defaultTemplate,
RetryablePredicate<Long> jobComplete, RetryablePredicate<VirtualMachine> virtualMachineRunning) {
Set<Network> networks = client.getNetworkClient().listNetworks();
if (networks.size() > 0) {
return createVirtualMachineInNetwork(get(networks, 0), client, jobComplete, virtualMachineRunning);
Network network = get(networks, 0);
return createVirtualMachineInNetwork(network,
defaultTemplateOrPreferredInZone(defaultTemplate, client, network.getZoneId()), client, jobComplete,
virtualMachineRunning);
} else {
return createVirtualMachineWithSecurityGroupInZone(
find(client.getZoneClient().listZones(), new Predicate<Zone>() {
long zoneId = find(client.getZoneClient().listZones(), new Predicate<Zone>() {
@Override
public boolean apply(Zone arg0) {
return arg0.isSecurityGroupsEnabled();
}
@Override
public boolean apply(Zone arg0) {
return arg0.isSecurityGroupsEnabled();
}
}).getId(), get(client.getSecurityGroupClient().listSecurityGroups(), 0).getId(), client, jobComplete,
}).getId();
return createVirtualMachineWithSecurityGroupInZone(zoneId,
defaultTemplateOrPreferredInZone(defaultTemplate, client, zoneId),
get(client.getSecurityGroupClient().listSecurityGroups(), 0).getId(), client, jobComplete,
virtualMachineRunning);
}
}
public static VirtualMachine createVirtualMachineWithSecurityGroupInZone(long zoneId, long groupId,
public static VirtualMachine createVirtualMachineWithSecurityGroupInZone(long zoneId, long templateId, long groupId,
CloudStackClient client, RetryablePredicate<Long> jobComplete,
RetryablePredicate<VirtualMachine> virtualMachineRunning) {
return createVirtualMachineWithOptionsInZone(new DeployVirtualMachineOptions().securityGroupId(groupId), zoneId,
client, jobComplete, virtualMachineRunning);
templateId, client, jobComplete, virtualMachineRunning);
}
public static VirtualMachine createVirtualMachineInNetwork(Network network, CloudStackClient client,
RetryablePredicate<Long> jobComplete, RetryablePredicate<VirtualMachine> virtualMachineRunning) {
public static VirtualMachine createVirtualMachineInNetwork(Network network, long templateId,
CloudStackClient client, RetryablePredicate<Long> jobComplete,
RetryablePredicate<VirtualMachine> virtualMachineRunning) {
DeployVirtualMachineOptions options = new DeployVirtualMachineOptions();
long zoneId = network.getZoneId();
options.networkId(network.getId());
return createVirtualMachineWithOptionsInZone(options, zoneId, client, jobComplete, virtualMachineRunning);
return createVirtualMachineWithOptionsInZone(options, zoneId, templateId, client, jobComplete,
virtualMachineRunning);
}
public static VirtualMachine createVirtualMachineWithOptionsInZone(DeployVirtualMachineOptions options,
final long zoneId, CloudStackClient client, RetryablePredicate<Long> jobComplete,
public static VirtualMachine createVirtualMachineWithOptionsInZone(DeployVirtualMachineOptions options, long zoneId,
long templateId, CloudStackClient client, RetryablePredicate<Long> jobComplete,
RetryablePredicate<VirtualMachine> virtualMachineRunning) {
// TODO enum, as this is way too easy to mess up.
Set<String> acceptableCategories = ImmutableSet.of("Ubuntu", "CentOS");
final Predicate<Template> hypervisorPredicate = new CorrectHypervisorForZone(client).apply(zoneId);
final Predicate<Template> osTypePredicate = new OSCategoryIn(client).apply(acceptableCategories);
@SuppressWarnings("unchecked")
Predicate<Template> templatePredicate = Predicates.<Template> and(TemplatePredicates.isReady(),
hypervisorPredicate, osTypePredicate);
Iterable<Template> templates = filter(
client.getTemplateClient().listTemplates(ListTemplatesOptions.Builder.zoneId(zoneId)), templatePredicate);
if (Iterables.any(templates, TemplatePredicates.isPasswordEnabled())) {
templates = filter(templates, TemplatePredicates.isPasswordEnabled());
}
if (Iterables.size(templates) == 0) {
throw new NoSuchElementException(templatePredicate.toString());
}
long templateId = get(templates, 0).getId();
long serviceOfferingId = DEFAULT_SIZE_ORDERING.min(client.getOfferingClient().listServiceOfferings()).getId();
System.out.printf("serviceOfferingId %d, templateId %d, zoneId %d, options %s%n", serviceOfferingId, templateId,
@ -158,7 +137,8 @@ public class VirtualMachineClientLiveTest extends BaseCloudStackClientLiveTest {
@SuppressWarnings("unchecked")
public void testCreateVirtualMachine() throws Exception {
vm = createVirtualMachine(client, jobComplete, virtualMachineRunning);
Long templateId = (imageId != null && !"".equals(imageId)) ? new Long(imageId) : null;
vm = createVirtualMachine(client, templateId, jobComplete, virtualMachineRunning);
if (vm.getPassword() != null) {
conditionallyCheckSSH();
}

View File

@ -0,0 +1,113 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.cloudstack.functions;
import static com.google.common.collect.Iterables.find;
import static org.testng.Assert.assertEquals;
import java.util.NoSuchElementException;
import org.jclouds.cloudstack.compute.config.CloudStackComputeServiceContextModule.GetIPForwardingRuleByVirtualMachine;
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.features.NATClientLiveTest;
import org.jclouds.cloudstack.features.VirtualMachineClientLiveTest;
import org.jclouds.cloudstack.predicates.NetworkPredicates;
import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.domain.Credentials;
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;
import com.google.common.cache.CacheBuilder;
/**
* Tests behavior of {@code StaticNATVirtualMachineInNetwork}
*
* @author Adrian Cole
*/
@Test(groups = "live", singleThreaded = true, testName = "StaticNATVirtualMachineInNetworkLiveTest")
public class StaticNATVirtualMachineInNetworkLiveTest extends NATClientLiveTest {
private PublicIPAddress ip = null;
private VirtualMachine vm;
private IPForwardingRule rule;
private Network network;
private boolean networksDisabled;
@BeforeGroups(groups = "live")
public void setupClient() {
super.setupClient();
prefix += "nat";
try {
network = find(client.getNetworkClient().listNetworks(), NetworkPredicates.supportsStaticNAT());
Long defaultTemplate = (imageId != null && !"".equals(imageId)) ? new Long(imageId) : null;
vm = VirtualMachineClientLiveTest.createVirtualMachineInNetwork(network,
defaultTemplateOrPreferredInZone(defaultTemplate, client, network.getZoneId()), client, jobComplete,
virtualMachineRunning);
if (vm.getPassword() != null)
password = vm.getPassword();
} catch (NoSuchElementException e) {
networksDisabled = true;
}
}
public void testCreateIPForwardingRule() throws Exception {
if (networksDisabled)
return;
ip = new StaticNATVirtualMachineInNetwork(client, reuseOrAssociate, jobComplete, CacheBuilder.newBuilder()
.<Long, IPForwardingRule> build(new GetIPForwardingRuleByVirtualMachine(client)), network).apply(vm);
rule = client.getNATClient().getIPForwardingRuleForIPAddress(ip.getId());
assertEquals(rule.getIPAddressId(), ip.getId());
assertEquals(rule.getVirtualMachineId(), vm.getId());
assertEquals(rule.getStartPort(), 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();
}
}
@AfterGroups(groups = "live")
protected void tearDown() {
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());
}
super.tearDown();
}
}

View File

@ -75,6 +75,17 @@ public class CloudStackErrorHandlerTest {
IllegalStateException.class);
}
@Test
public void test431MakesResourceNotFoundExceptionOnDelete() {
assertCodeMakes(
"GET",
URI.create("https://api.ninefold.com/compute/v1.0/?response=json&command=deleteSSHKeyPair"),
431,
"",
"{ \"deletekeypairresponse\" : {\"errorcode\" : 431, \"errortext\" : \"A key pair with name 'adriancole-adapter-test-keypair' does not exist for account jclouds in domain id=457\"} }",
ResourceNotFoundException.class);
}
@Test
public void test409MakesIllegalStateException() {
assertCodeMakes("GET", URI.create("https://cloudstack.com/foo"), 409, "", "Conflict", IllegalStateException.class);