merged master
diff --git a/apis/cloudloadbalancers/src/test/java/org/jclouds/cloudloadbalancers/features/BaseCloudLoadBalancersAsyncClientTest.java b/apis/cloudloadbalancers/src/test/java/org/jclouds/cloudloadbalancers/features/BaseCloudLoadBalancersAsyncClientTest.java
index 05280b7..a619a26 100644
--- a/apis/cloudloadbalancers/src/test/java/org/jclouds/cloudloadbalancers/features/BaseCloudLoadBalancersAsyncClientTest.java
+++ b/apis/cloudloadbalancers/src/test/java/org/jclouds/cloudloadbalancers/features/BaseCloudLoadBalancersAsyncClientTest.java
@@ -30,6 +30,7 @@
import org.jclouds.cloudloadbalancers.config.CloudLoadBalancersRestClientModule;
import org.jclouds.cloudloadbalancers.functions.ConvertLB;
import org.jclouds.cloudloadbalancers.reference.Region;
+import org.jclouds.domain.Credentials;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.RequiresHttp;
import org.jclouds.internal.ClassMethodArgs;
@@ -78,7 +79,7 @@
install(new OpenStackAuthenticationModule() {
@Override
protected Supplier<AuthenticationResponse> provideAuthenticationResponseSupplier(
- final LoadingCache<String,AuthenticationResponse> cache) {
+ LoadingCache<Credentials, AuthenticationResponse> cache, Credentials in) {
return Suppliers.ofInstance(new AuthenticationResponse("token", ImmutableMap.<String, URI> of()));
}
});
diff --git a/apis/cloudservers/src/test/java/org/jclouds/cloudservers/handlers/RetryOnRenewExpectTest.java b/apis/cloudservers/src/test/java/org/jclouds/cloudservers/handlers/RetryOnRenewExpectTest.java
index 0192555..1f4d2ce 100644
--- a/apis/cloudservers/src/test/java/org/jclouds/cloudservers/handlers/RetryOnRenewExpectTest.java
+++ b/apis/cloudservers/src/test/java/org/jclouds/cloudservers/handlers/RetryOnRenewExpectTest.java
@@ -67,6 +67,19 @@
.put("Content-Length", "0")
.build()).build();
+ HttpRequest deleteImage = HttpRequest.builder().method("DELETE").endpoint(
+ URI.create("https://servers.api.rackspacecloud.com/v1.0/413274/images/11?now=1257695648897")).headers(
+ ImmutableMultimap.<String, String> builder()
+ .put("X-Auth-Token", authToken).build()).build();
+
+ HttpResponse pleaseRenew = HttpResponse.builder().statusCode(401)
+ .message("HTTP/1.1 401 Unauthorized")
+ .payload(Payloads.newStringPayload("[{\"unauthorized\":{\"message\":\"Invalid authentication token. Please renew.\",\"code\":401}}]"))
+ .build();
+
+ // second auth uses same creds as initial one
+ HttpRequest redoAuth = initialAuth;
+
HttpResponse responseWithUrls2 = HttpResponse.builder().statusCode(204).message("HTTP/1.1 204 No Content")
.headers(ImmutableMultimap.<String,String>builder()
.put("Server", "Apache/2.2.3 (Red Hat)")
@@ -82,17 +95,7 @@
.put("X-CDN-Management-Url", "https://cdn1.clouddrive.com/v1/MossoCloudFS_dc1f419c-5059-4c87-a389-3f2e33a77b22")
.put("Content-Length", "0")
.build()).build();
-
- HttpRequest deleteImage = HttpRequest.builder().method("DELETE").endpoint(
- URI.create("https://servers.api.rackspacecloud.com/v1.0/413274/images/11?now=1257695648897")).headers(
- ImmutableMultimap.<String, String> builder()
- .put("X-Auth-Token", authToken).build()).build();
-
- HttpResponse pleaseRenew = HttpResponse.builder().statusCode(401)
- .message("HTTP/1.1 401 Unauthorized")
- .payload(Payloads.newStringPayload("[{\"unauthorized\":{\"message\":\"Invalid authentication token. Please renew.\",\"code\":401}}]"))
- .build();
-
+
HttpRequest deleteImage2 = HttpRequest.builder().method("DELETE").endpoint(
URI.create("https://servers.api.rackspacecloud.com/v1.0/413274/images/11?now=1257695648897")).headers(
ImmutableMultimap.<String, String> builder()
@@ -101,7 +104,7 @@
HttpResponse imageDeleted = HttpResponse.builder().statusCode(204).message("HTTP/1.1 204 No Content").build();
CloudServersClient clientWhenImageExists = orderedRequestsSendResponses(initialAuth, responseWithUrls,
- deleteImage, pleaseRenew, initialAuth, responseWithUrls2, deleteImage2, imageDeleted);
+ deleteImage, pleaseRenew, redoAuth, responseWithUrls2, deleteImage2, imageDeleted);
assert clientWhenImageExists.deleteImage(11);
}
@@ -151,7 +154,7 @@
}
// FIXME stack trace shows the AuthorizationException, but it's buried inside a guice TestException
- @Test(enabled=false, expectedExceptions=AuthorizationException.class)
+ @Test(expectedExceptions=AuthorizationException.class)
public void testDoesNotReauthenticateOnAuthentication401() {
HttpRequest initialAuth = HttpRequest.builder().method("GET").endpoint(URI.create("https://auth/v1.0"))
.headers(
@@ -166,7 +169,7 @@
.payload(Payloads.newStringPayload("[{\"unauthorized\":{\"message\":\"A different message implying fatal.\",\"code\":401}}]"))
.build();
- CloudServersClient client = orderedRequestsSendResponses(initialAuth, unauthResponse);
+ CloudServersClient client = requestSendsResponse(initialAuth, unauthResponse);
client.deleteImage(11);
}
diff --git a/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/CloudSigmaComputeServiceAdapter.java b/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/CloudSigmaComputeServiceAdapter.java
index d67a798..6886561 100644
--- a/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/CloudSigmaComputeServiceAdapter.java
+++ b/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/CloudSigmaComputeServiceAdapter.java
@@ -32,6 +32,8 @@
import org.jclouds.Constants;
import org.jclouds.cloudsigma.CloudSigmaClient;
+import org.jclouds.cloudsigma.compute.options.CloudSigmaTemplateOptions;
+import org.jclouds.cloudsigma.domain.AffinityType;
import org.jclouds.cloudsigma.domain.Device;
import org.jclouds.cloudsigma.domain.DriveInfo;
import org.jclouds.cloudsigma.domain.DriveType;
@@ -69,7 +71,7 @@
/**
* defines the connection between the {@link CloudSigmaClient} implementation
* and the jclouds {@link ComputeService}
- *
+ *
*/
@Singleton
public class CloudSigmaComputeServiceAdapter implements
@@ -109,9 +111,15 @@
@Override
public NodeAndInitialCredentials<ServerInfo> createNodeWithGroupEncodedIntoName(String tag, String name, Template template) {
long bootSize = (long) (template.getHardware().getVolumes().get(0).getSize() * 1024 * 1024 * 1024l);
- logger.debug(">> imaging boot drive source(%s) bytes(%d)", template.getImage().getId(), bootSize);
+ AffinityType affinityType = AffinityType.HDD;
+ if (template.getOptions() instanceof CloudSigmaTemplateOptions) {
+ CloudSigmaTemplateOptions options = CloudSigmaTemplateOptions.class.cast(template.getOptions());
+ affinityType = options.getDiskDriveAffinity();
+ }
+ logger.debug(">> imaging boot drive source(%s) bytes(%d) affinityType(%s)",
+ template.getImage().getId(), bootSize, affinityType);
DriveInfo drive = client.cloneDrive(template.getImage().getId(), template.getImage().getId(),
- new CloneDriveOptions().size(bootSize));
+ new CloneDriveOptions().size(bootSize).affinity(affinityType));
boolean success = driveNotClaimed.apply(drive);
logger.debug("<< image(%s) complete(%s)", drive.getUuid(), success);
if (!success) {
@@ -152,7 +160,7 @@
}
}).ids(id).ram(ram).processors(ImmutableList.of(new Processor(1, cpu)))
- .volumes(ImmutableList.<Volume> of(new VolumeImpl(size, true, true))).build());
+ .volumes(ImmutableList.<Volume>of(new VolumeImpl(size, true, true))).build());
}
return hardware.build();
}
diff --git a/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/CloudSigmaTemplateBuilderImpl.java b/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/CloudSigmaTemplateBuilderImpl.java
new file mode 100644
index 0000000..57a31f2
--- /dev/null
+++ b/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/CloudSigmaTemplateBuilderImpl.java
@@ -0,0 +1,46 @@
+/**
+ * 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.cloudsigma.compute;
+
+import com.google.common.base.Supplier;
+import org.jclouds.collect.Memoized;
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.TemplateBuilder;
+import org.jclouds.compute.domain.internal.TemplateBuilderImpl;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.domain.Location;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Provider;
+import java.util.Set;
+
+/**
+ * @author Andrei Savu
+ */
+public class CloudSigmaTemplateBuilderImpl extends TemplateBuilderImpl {
+ @Inject
+ public CloudSigmaTemplateBuilderImpl(@Memoized Supplier<Set<? extends Location>> locations,
+ @Memoized Supplier<Set<? extends Image>> images, @Memoized Supplier<Set<? extends Hardware>> hardwares,
+ Supplier<Location> defaultLocation2, @Named("DEFAULT") Provider<TemplateOptions> optionsProvider,
+ @Named("DEFAULT") Provider<TemplateBuilder> defaultTemplateProvider) {
+ super(locations, images, hardwares, defaultLocation2, optionsProvider, defaultTemplateProvider);
+ }
+}
diff --git a/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/config/CloudSigmaComputeServiceContextModule.java b/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/config/CloudSigmaComputeServiceContextModule.java
index 730ec4f..29d62af 100644
--- a/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/config/CloudSigmaComputeServiceContextModule.java
+++ b/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/config/CloudSigmaComputeServiceContextModule.java
@@ -26,12 +26,14 @@
import org.jclouds.cloudsigma.CloudSigmaAsyncClient;
import org.jclouds.cloudsigma.CloudSigmaClient;
import org.jclouds.cloudsigma.compute.CloudSigmaComputeServiceAdapter;
+import org.jclouds.cloudsigma.compute.CloudSigmaTemplateBuilderImpl;
import org.jclouds.cloudsigma.compute.functions.ParseOsFamilyVersion64BitFromImageName;
import org.jclouds.cloudsigma.compute.functions.PreinstalledDiskToImage;
import org.jclouds.cloudsigma.compute.functions.ServerInfoToNodeMetadata;
import org.jclouds.cloudsigma.compute.functions.ServerInfoToNodeMetadata.DeviceToVolume;
import org.jclouds.cloudsigma.compute.functions.ServerInfoToNodeMetadata.FindImageForId;
import org.jclouds.cloudsigma.compute.functions.ServerInfoToNodeMetadata.GetImageIdFromServer;
+import org.jclouds.cloudsigma.compute.options.CloudSigmaTemplateOptions;
import org.jclouds.cloudsigma.domain.Device;
import org.jclouds.cloudsigma.domain.DriveInfo;
import org.jclouds.cloudsigma.domain.Server;
@@ -46,6 +48,7 @@
import org.jclouds.compute.domain.OsFamilyVersion64Bit;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.domain.Volume;
+import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.Location;
import org.jclouds.functions.IdentityFunction;
@@ -104,6 +107,8 @@
}).to(ParseOsFamilyVersion64BitFromImageName.class);
bind(new TypeLiteral<Supplier<Location>>() {
}).to(OnlyLocationOrFirstZone.class);
+ bind(TemplateBuilder.class)
+ .to(CloudSigmaTemplateBuilderImpl.class);
}
@Provides
@@ -134,4 +139,10 @@
return new RetryablePredicate<DriveInfo>(Predicates.not(driveClaimed), timeouts.nodeRunning, 1000,
TimeUnit.MILLISECONDS);
}
+
+ @Provides
+ @Singleton
+ protected TemplateOptions templateOptions() {
+ return new CloudSigmaTemplateOptions();
+ }
}
\ No newline at end of file
diff --git a/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/functions/ServerInfoToNodeMetadata.java b/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/functions/ServerInfoToNodeMetadata.java
index 4c433c9..7e6bfc8 100644
--- a/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/functions/ServerInfoToNodeMetadata.java
+++ b/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/functions/ServerInfoToNodeMetadata.java
@@ -21,7 +21,6 @@
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.compute.util.ComputeServiceUtils.parseGroupFromName;
-import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -102,7 +101,7 @@
}
builder.hardware(new HardwareBuilder().ids(from.getUuid())
.processors(ImmutableList.of(new Processor(1, from.getCpu()))).ram(from.getMem())
- .volumes((List) ImmutableList.of(Iterables.transform(from.getDevices().values(), deviceToVolume))).build());
+ .volumes(Iterables.transform(from.getDevices().values(), deviceToVolume)).build());
builder.state(serverStatusToNodeState.get(from.getStatus()));
builder.publicAddresses(ImmutableSet.<String> of(from.getVnc().getIp()));
builder.privateAddresses(ImmutableSet.<String> of());
@@ -133,7 +132,7 @@
} catch (UncheckedExecutionException e) {
logger.warn(e, "error finding drive %s: %s", input.getDriveUuid(), e.getMessage());
}
- return new VolumeBuilder().durable(true).type(Volume.Type.NAS).build();
+ return builder.durable(true).type(Volume.Type.NAS).build();
}
}
diff --git a/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/options/CloudSigmaTemplateOptions.java b/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/options/CloudSigmaTemplateOptions.java
new file mode 100644
index 0000000..97e5808
--- /dev/null
+++ b/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/options/CloudSigmaTemplateOptions.java
@@ -0,0 +1,349 @@
+/**
+ * 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.cloudsigma.compute.options;
+
+import org.jclouds.cloudsigma.domain.AffinityType;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.domain.Credentials;
+import org.jclouds.domain.LoginCredentials;
+import org.jclouds.io.Payload;
+import org.jclouds.scriptbuilder.domain.Statement;
+
+import java.util.Map;
+
+public class CloudSigmaTemplateOptions extends TemplateOptions implements Cloneable {
+
+ public static final CloudSigmaTemplateOptions NONE = new CloudSigmaTemplateOptions();
+
+ private AffinityType diskDriveAffinity = AffinityType.HDD;
+
+ public CloudSigmaTemplateOptions diskDriveAffinity(AffinityType diskDriveAffinity) {
+ this.diskDriveAffinity = diskDriveAffinity;
+ return this;
+ }
+
+ public AffinityType getDiskDriveAffinity() {
+ return diskDriveAffinity;
+ }
+
+ @Override
+ public CloudSigmaTemplateOptions clone() {
+ CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
+ copyTo(options);
+ return options;
+ }
+
+ @Override
+ public void copyTo(TemplateOptions to) {
+ super.copyTo(to);
+ if (to instanceof CloudSigmaTemplateOptions) {
+ CloudSigmaTemplateOptions cTo = CloudSigmaTemplateOptions.class.cast(to);
+ cTo.diskDriveAffinity(getDiskDriveAffinity());
+ }
+ }
+
+ public static class Builder {
+
+ /**
+ * @see CloudSigmaTemplateOptions#diskDriveAffinity
+ */
+ public static CloudSigmaTemplateOptions diskDriveAffinity(AffinityType diskDriveAffinity) {
+ CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
+ return options.diskDriveAffinity(diskDriveAffinity);
+ }
+
+ // methods that only facilitate returning the correct object type
+
+ /**
+ * @see TemplateOptions#inboundPorts
+ */
+ public static CloudSigmaTemplateOptions inboundPorts(int... ports) {
+ CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
+ return CloudSigmaTemplateOptions.class.cast(options.inboundPorts(ports));
+ }
+
+ /**
+ * @see TemplateOptions#port
+ */
+ public static CloudSigmaTemplateOptions blockOnPort(int port, int seconds) {
+ CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
+ return CloudSigmaTemplateOptions.class.cast(options.blockOnPort(port, seconds));
+ }
+
+ /**
+ * @see TemplateOptions#installPrivateKey
+ */
+ public static CloudSigmaTemplateOptions installPrivateKey(String rsaKey) {
+ CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
+ return CloudSigmaTemplateOptions.class.cast(options.installPrivateKey(rsaKey));
+ }
+
+ /**
+ * @see TemplateOptions#authorizePublicKey
+ */
+ public static CloudSigmaTemplateOptions authorizePublicKey(String rsaKey) {
+ CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
+ return CloudSigmaTemplateOptions.class.cast(options.authorizePublicKey(rsaKey));
+ }
+
+ /**
+ * @see TemplateOptions#userMetadata(Map)
+ */
+ public static CloudSigmaTemplateOptions userMetadata(Map<String, String> userMetadata) {
+ CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
+ return CloudSigmaTemplateOptions.class.cast(options.userMetadata(userMetadata));
+ }
+
+ @Deprecated
+ public static CloudSigmaTemplateOptions overrideLoginUserWith(String user) {
+ CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
+ return options.overrideLoginUserWith(user);
+ }
+
+ public static CloudSigmaTemplateOptions overrideLoginUser(String user) {
+ CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
+ return options.overrideLoginUser(user);
+ }
+
+ public static CloudSigmaTemplateOptions overrideLoginPassword(String password) {
+ CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
+ return options.overrideLoginPassword(password);
+ }
+
+ public static CloudSigmaTemplateOptions overrideLoginPrivateKey(String privateKey) {
+ CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
+ return options.overrideLoginPrivateKey(privateKey);
+ }
+
+ public static CloudSigmaTemplateOptions overrideAuthenticateSudo(boolean authenticateSudo) {
+ CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
+ return options.overrideAuthenticateSudo(authenticateSudo);
+ }
+
+ @Deprecated
+ public static CloudSigmaTemplateOptions overrideLoginCredentialWith(String credential) {
+ CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
+ return options.overrideLoginCredentialWith(credential);
+ }
+
+ @Deprecated
+ public static CloudSigmaTemplateOptions overrideCredentialsWith(Credentials credentials) {
+ CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
+ return options.overrideCredentialsWith(credentials);
+ }
+
+ public static CloudSigmaTemplateOptions overrideLoginCredentials(LoginCredentials credentials) {
+ CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
+ return options.overrideLoginCredentials(credentials);
+ }
+ }
+
+ // methods that only facilitate returning the correct object type
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public CloudSigmaTemplateOptions blockOnPort(int port, int seconds) {
+ return CloudSigmaTemplateOptions.class.cast(super.blockOnPort(port, seconds));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public CloudSigmaTemplateOptions inboundPorts(int... ports) {
+ return CloudSigmaTemplateOptions.class.cast(super.inboundPorts(ports));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public CloudSigmaTemplateOptions authorizePublicKey(String publicKey) {
+ return CloudSigmaTemplateOptions.class.cast(super.authorizePublicKey(publicKey));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public CloudSigmaTemplateOptions installPrivateKey(String privateKey) {
+ return CloudSigmaTemplateOptions.class.cast(super.installPrivateKey(privateKey));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Deprecated
+ @Override
+ public CloudSigmaTemplateOptions runScript(Payload script) {
+ return CloudSigmaTemplateOptions.class.cast(super.runScript(script));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public CloudSigmaTemplateOptions blockUntilRunning(boolean blockUntilRunning) {
+ return CloudSigmaTemplateOptions.class.cast(super.blockUntilRunning(blockUntilRunning));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public CloudSigmaTemplateOptions dontAuthorizePublicKey() {
+ return CloudSigmaTemplateOptions.class.cast(super.dontAuthorizePublicKey());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public CloudSigmaTemplateOptions nameTask(String name) {
+ return CloudSigmaTemplateOptions.class.cast(super.nameTask(name));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public CloudSigmaTemplateOptions runAsRoot(boolean runAsRoot) {
+ return CloudSigmaTemplateOptions.class.cast(super.runAsRoot(runAsRoot));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public CloudSigmaTemplateOptions runScript(Statement script) {
+ return CloudSigmaTemplateOptions.class.cast(super.runScript(script));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Deprecated
+ @Override
+ public CloudSigmaTemplateOptions overrideCredentialsWith(Credentials overridingCredentials) {
+ return CloudSigmaTemplateOptions.class.cast(super.overrideCredentialsWith(overridingCredentials));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Deprecated
+ @Override
+ public CloudSigmaTemplateOptions overrideLoginUserWith(String loginUser) {
+ return CloudSigmaTemplateOptions.class.cast(super.overrideLoginUserWith(loginUser));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Deprecated
+ @Override
+ public CloudSigmaTemplateOptions overrideLoginCredentialWith(String loginCredential) {
+ return CloudSigmaTemplateOptions.class.cast(super.overrideLoginCredentialWith(loginCredential));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public CloudSigmaTemplateOptions overrideLoginCredentials(LoginCredentials overridingCredentials) {
+ return CloudSigmaTemplateOptions.class.cast(super.overrideLoginCredentials(overridingCredentials));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public CloudSigmaTemplateOptions overrideLoginPassword(String password) {
+ return CloudSigmaTemplateOptions.class.cast(super.overrideLoginPassword(password));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public CloudSigmaTemplateOptions overrideLoginPrivateKey(String privateKey) {
+ return CloudSigmaTemplateOptions.class.cast(super.overrideLoginPrivateKey(privateKey));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public CloudSigmaTemplateOptions overrideLoginUser(String loginUser) {
+ return CloudSigmaTemplateOptions.class.cast(super.overrideLoginUser(loginUser));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public CloudSigmaTemplateOptions overrideAuthenticateSudo(boolean authenticateSudo) {
+ return CloudSigmaTemplateOptions.class.cast(super.overrideAuthenticateSudo(authenticateSudo));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public CloudSigmaTemplateOptions userMetadata(Map<String, String> userMetadata) {
+ return CloudSigmaTemplateOptions.class.cast(super.userMetadata(userMetadata));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public CloudSigmaTemplateOptions userMetadata(String key, String value) {
+ return CloudSigmaTemplateOptions.class.cast(super.userMetadata(key, value));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ if (!super.equals(o)) return false;
+
+ CloudSigmaTemplateOptions that = (CloudSigmaTemplateOptions) o;
+
+ if (diskDriveAffinity != that.diskDriveAffinity) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = super.hashCode();
+ result = 31 * result + (diskDriveAffinity != null ? diskDriveAffinity.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "CloudSigmaTemplateOptions{" +
+ "diskDriveAffinity=" + diskDriveAffinity +
+ '}';
+ }
+}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackDomainAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackDomainAsyncClient.java
index fc89a31..941ee55 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackDomainAsyncClient.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackDomainAsyncClient.java
@@ -19,6 +19,7 @@
package org.jclouds.cloudstack;
import org.jclouds.cloudstack.features.DomainAccountAsyncClient;
+import org.jclouds.cloudstack.features.DomainDomainAsyncClient;
import org.jclouds.cloudstack.features.DomainLimitAsyncClient;
import org.jclouds.cloudstack.features.DomainUserAsyncClient;
import org.jclouds.rest.annotations.Delegate;
@@ -55,4 +56,10 @@
@Delegate
DomainUserAsyncClient getUserClient();
+ /**
+ * Provides asynchronous access to Domains
+ */
+ @Delegate
+ DomainDomainAsyncClient getDomainClient();
+
}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackDomainClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackDomainClient.java
index 62a29ea..10537a5 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackDomainClient.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackDomainClient.java
@@ -21,6 +21,7 @@
import java.util.concurrent.TimeUnit;
import org.jclouds.cloudstack.features.DomainAccountClient;
+import org.jclouds.cloudstack.features.DomainDomainClient;
import org.jclouds.cloudstack.features.DomainLimitClient;
import org.jclouds.cloudstack.features.DomainUserClient;
import org.jclouds.concurrent.Timeout;
@@ -58,4 +59,10 @@
*/
@Delegate
DomainUserClient getUserClient();
+
+ /**
+ * Provides synchronous access to Domains
+ */
+ @Delegate
+ DomainDomainClient getDomainClient();
}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackGlobalAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackGlobalAsyncClient.java
index b73d74a..28f23cb 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackGlobalAsyncClient.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackGlobalAsyncClient.java
@@ -23,6 +23,7 @@
import org.jclouds.cloudstack.features.GlobalCapacityAsyncClient;
import org.jclouds.cloudstack.features.GlobalConfigurationAsyncClient;
import org.jclouds.cloudstack.features.GlobalConfigurationClient;
+import org.jclouds.cloudstack.features.GlobalDomainAsyncClient;
import org.jclouds.cloudstack.features.GlobalHostAsyncClient;
import org.jclouds.cloudstack.features.GlobalOfferingAsyncClient;
import org.jclouds.cloudstack.features.GlobalStoragePoolAsyncClient;
@@ -99,4 +100,11 @@
@Delegate
@Override
GlobalConfigurationAsyncClient getConfigurationClient();
+
+ /**
+ * Provides asynchronous access to Domain
+ */
+ @Delegate
+ @Override
+ GlobalDomainAsyncClient getDomainClient();
}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackGlobalClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackGlobalClient.java
index b6dc916..135a2cb 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackGlobalClient.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackGlobalClient.java
@@ -24,6 +24,7 @@
import org.jclouds.cloudstack.features.GlobalAlertClient;
import org.jclouds.cloudstack.features.GlobalCapacityClient;
import org.jclouds.cloudstack.features.GlobalConfigurationClient;
+import org.jclouds.cloudstack.features.GlobalDomainClient;
import org.jclouds.cloudstack.features.GlobalHostClient;
import org.jclouds.cloudstack.features.GlobalOfferingClient;
import org.jclouds.cloudstack.features.GlobalStoragePoolClient;
@@ -102,4 +103,11 @@
@Delegate
@Override
GlobalConfigurationClient getConfigurationClient();
+
+ /**
+ * Provides synchronous access to Domain
+ */
+ @Delegate
+ @Override
+ GlobalDomainClient getDomainClient();
}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackRestClientModule.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackRestClientModule.java
index 2c28734..62d4b1b 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackRestClientModule.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackRestClientModule.java
@@ -40,6 +40,8 @@
import org.jclouds.cloudstack.features.ConfigurationClient;
import org.jclouds.cloudstack.features.DomainAccountAsyncClient;
import org.jclouds.cloudstack.features.DomainAccountClient;
+import org.jclouds.cloudstack.features.DomainDomainAsyncClient;
+import org.jclouds.cloudstack.features.DomainDomainClient;
import org.jclouds.cloudstack.features.DomainLimitAsyncClient;
import org.jclouds.cloudstack.features.DomainLimitClient;
import org.jclouds.cloudstack.features.DomainUserAsyncClient;
@@ -56,6 +58,8 @@
import org.jclouds.cloudstack.features.GlobalCapacityClient;
import org.jclouds.cloudstack.features.GlobalConfigurationAsyncClient;
import org.jclouds.cloudstack.features.GlobalConfigurationClient;
+import org.jclouds.cloudstack.features.GlobalDomainAsyncClient;
+import org.jclouds.cloudstack.features.GlobalDomainClient;
import org.jclouds.cloudstack.features.GlobalHostAsyncClient;
import org.jclouds.cloudstack.features.GlobalHostClient;
import org.jclouds.cloudstack.features.GlobalOfferingAsyncClient;
@@ -144,6 +148,8 @@
.put(AccountClient.class, AccountAsyncClient.class)//
.put(DomainAccountClient.class, DomainAccountAsyncClient.class)//
.put(DomainUserClient.class, DomainUserAsyncClient.class)//
+ .put(DomainDomainClient.class, DomainDomainAsyncClient.class)//
+ .put(GlobalDomainClient.class, GlobalDomainAsyncClient.class)//
.put(GlobalAccountClient.class, GlobalAccountAsyncClient.class)//
.put(GlobalUserClient.class, GlobalUserAsyncClient.class)//
.put(EventClient.class, EventAsyncClient.class)//
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Domain.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Domain.java
new file mode 100644
index 0000000..3e1fc7a
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Domain.java
@@ -0,0 +1,192 @@
+/**
+ * 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.domain;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Representation of the API domain response
+ *
+ * @author Andrei Savu
+ */
+public class Domain implements Comparable<Domain> {
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+
+ private long id;
+ private boolean hasChild;
+ private long level;
+ private String name;
+ private String networkDomain;
+ private long parentDomainId;
+ private String parentDomainName;
+
+ public Builder id(long id) {
+ this.id = id;
+ return this;
+ }
+
+ public Builder hasChild(boolean hasChild) {
+ this.hasChild = hasChild;
+ return this;
+ }
+
+ public Builder level(long level) {
+ this.level = level;
+ return this;
+ }
+
+ public Builder name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public Builder networkDomain(String networkDomain) {
+ this.networkDomain = networkDomain;
+ return this;
+ }
+
+ public Builder parentDomainId(long parentDomainId) {
+ this.parentDomainId = parentDomainId;
+ return this;
+ }
+
+ public Builder parentDomainName(String parentDomainName) {
+ this.parentDomainName = parentDomainName;
+ return this;
+ }
+
+ public Domain build() {
+ return new Domain(id, hasChild, level, name, networkDomain,
+ parentDomainId, parentDomainName);
+ }
+ }
+
+ // for deserialization
+ Domain() {
+ }
+
+ private long id;
+ @SerializedName("haschild")
+ private boolean hasChild;
+ private long level;
+ private String name;
+ @SerializedName("networkdomain")
+ private String networkDomain;
+ @SerializedName("parentdomainid")
+ private long parentDomainId;
+ @SerializedName("parentdomainname")
+ private String parentDomainName;
+
+ public Domain(long id, boolean hasChild, long level, String name, String networkDomain,
+ long parentDomainId, String parentDomainName) {
+ this.id = id;
+ this.hasChild = hasChild;
+ this.level = level;
+ this.name = name;
+ this.networkDomain = networkDomain;
+ this.parentDomainId = parentDomainId;
+ this.parentDomainName = parentDomainName;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public boolean hasChild() {
+ return hasChild;
+ }
+
+ public long getLevel() {
+ return level;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getNetworkDomain() {
+ return networkDomain;
+ }
+
+ public long getParentDomainId() {
+ return parentDomainId;
+ }
+
+ public String getParentDomainName() {
+ return parentDomainName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Domain domain = (Domain) o;
+
+ if (hasChild != domain.hasChild) return false;
+ if (id != domain.id) return false;
+ if (level != domain.level) return false;
+ if (parentDomainId != domain.parentDomainId) return false;
+ if (name != null ? !name.equals(domain.name) : domain.name != null)
+ return false;
+ if (networkDomain != null ? !networkDomain.equals(domain.networkDomain) : domain.networkDomain != null)
+ return false;
+ if (parentDomainName != null ? !parentDomainName.equals(domain.parentDomainName) : domain.parentDomainName != null)
+ return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (int) (id ^ (id >>> 32));
+ result = 31 * result + (hasChild ? 1 : 0);
+ result = 31 * result + (int) (level ^ (level >>> 32));
+ result = 31 * result + (name != null ? name.hashCode() : 0);
+ result = 31 * result + (networkDomain != null ? networkDomain.hashCode() : 0);
+ result = 31 * result + (int) (parentDomainId ^ (parentDomainId >>> 32));
+ result = 31 * result + (parentDomainName != null ? parentDomainName.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "Domain{" +
+ "id=" + id +
+ ", hasChild=" + hasChild +
+ ", level=" + level +
+ ", name='" + name + '\'' +
+ ", networkDomain='" + networkDomain + '\'' +
+ ", parentDomainId=" + parentDomainId +
+ ", parentDomainName='" + parentDomainName + '\'' +
+ '}';
+ }
+
+ @Override
+ public int compareTo(Domain arg0) {
+ return new Long(id).compareTo(arg0.getId());
+ }
+
+}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Host.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Host.java
index 8b59238..3a01ca8 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Host.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Host.java
@@ -708,6 +708,59 @@
}
@Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Host host = (Host) o;
+
+ if (averageLoad != host.averageLoad) return false;
+ if (clusterId != host.clusterId) return false;
+ if (cpuNumber != host.cpuNumber) return false;
+ if (cpuSpeed != host.cpuSpeed) return false;
+ if (Float.compare(host.cpuWithOverProvisioning, cpuWithOverProvisioning) != 0) return false;
+ if (diskSizeAllocated != host.diskSizeAllocated) return false;
+ if (diskSizeTotal != host.diskSizeTotal) return false;
+ if (hasEnoughCapacity != host.hasEnoughCapacity) return false;
+ if (id != host.id) return false;
+ if (jobId != host.jobId) return false;
+ if (localStorageActive != host.localStorageActive) return false;
+ if (managementServerId != host.managementServerId) return false;
+ if (memoryAllocated != host.memoryAllocated) return false;
+ if (memoryTotal != host.memoryTotal) return false;
+ if (memoryUsed != host.memoryUsed) return false;
+ if (networkKbsRead != host.networkKbsRead) return false;
+ if (networkKbsWrite != host.networkKbsWrite) return false;
+ if (osCategoryId != host.osCategoryId) return false;
+ if (osCategoryName != host.osCategoryName) return false;
+ if (podId != host.podId) return false;
+ if (zoneId != host.zoneId) return false;
+ if (allocationState != host.allocationState) return false;
+ if (capabilities != null ? !capabilities.equals(host.capabilities) : host.capabilities != null) return false;
+ if (clusterName != null ? !clusterName.equals(host.clusterName) : host.clusterName != null) return false;
+ if (clusterType != host.clusterType) return false;
+ if (cpuAllocated != null ? !cpuAllocated.equals(host.cpuAllocated) : host.cpuAllocated != null) return false;
+ if (cpuUsed != null ? !cpuUsed.equals(host.cpuUsed) : host.cpuUsed != null) return false;
+ if (created != null ? !created.equals(host.created) : host.created != null) return false;
+ if (disconnected != null ? !disconnected.equals(host.disconnected) : host.disconnected != null) return false;
+ if (events != null ? !events.equals(host.events) : host.events != null) return false;
+ if (hostTags != null ? !hostTags.equals(host.hostTags) : host.hostTags != null) return false;
+ if (hypervisor != null ? !hypervisor.equals(host.hypervisor) : host.hypervisor != null) return false;
+ if (ipAddress != null ? !ipAddress.equals(host.ipAddress) : host.ipAddress != null) return false;
+ if (jobStatus != host.jobStatus) return false;
+ if (lastPinged != null ? !lastPinged.equals(host.lastPinged) : host.lastPinged != null) return false;
+ if (name != null ? !name.equals(host.name) : host.name != null) return false;
+ if (podName != null ? !podName.equals(host.podName) : host.podName != null) return false;
+ if (removed != null ? !removed.equals(host.removed) : host.removed != null) return false;
+ if (state != host.state) return false;
+ if (type != host.type) return false;
+ if (version != null ? !version.equals(host.version) : host.version != null) return false;
+ if (zoneName != null ? !zoneName.equals(host.zoneName) : host.zoneName != null) return false;
+
+ return true;
+ }
+
+ @Override
public int hashCode() {
int result = (int) (id ^ (id >>> 32));
result = 31 * result + (allocationState != null ? allocationState.hashCode() : 0);
@@ -720,7 +773,7 @@
result = 31 * result + cpuNumber;
result = 31 * result + cpuSpeed;
result = 31 * result + (cpuUsed != null ? cpuUsed.hashCode() : 0);
- result = 31 * result + (int) cpuWithOverProvisioning;
+ result = 31 * result + (cpuWithOverProvisioning != +0.0f ? Float.floatToIntBits(cpuWithOverProvisioning) : 0);
result = 31 * result + (created != null ? created.hashCode() : 0);
result = 31 * result + (disconnected != null ? disconnected.hashCode() : 0);
result = 31 * result + (int) (diskSizeAllocated ^ (diskSizeAllocated >>> 32));
@@ -755,89 +808,19 @@
}
@Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- Host host = (Host) o;
-
- if (averageLoad != host.averageLoad) return false;
- if (clusterId != host.clusterId) return false;
- if (cpuAllocated != host.cpuAllocated) return false;
- if (cpuNumber != host.cpuNumber) return false;
- if (cpuSpeed != host.cpuSpeed) return false;
- if (cpuUsed != host.cpuUsed) return false;
- if (cpuWithOverProvisioning != host.cpuWithOverProvisioning) return false;
- if (disconnected != host.disconnected) return false;
- if (diskSizeAllocated != host.diskSizeAllocated) return false;
- if (diskSizeTotal != host.diskSizeTotal) return false;
- if (hasEnoughCapacity != host.hasEnoughCapacity) return false;
- if (id != host.id) return false;
- if (localStorageActive != host.localStorageActive) return false;
- if (jobId != host.jobId) return false;
- if (managementServerId != host.managementServerId) return false;
- if (memoryAllocated != host.memoryAllocated) return false;
- if (memoryTotal != host.memoryTotal) return false;
- if (memoryUsed != host.memoryUsed) return false;
- if (networkKbsRead != host.networkKbsRead) return false;
- if (networkKbsWrite != host.networkKbsWrite) return false;
- if (osCategoryId != host.osCategoryId) return false;
- if (osCategoryName != host.osCategoryName) return false;
- if (podId != host.podId) return false;
- if (zoneId != host.zoneId) return false;
- if (allocationState != null ? !allocationState.equals(host.allocationState) : host.allocationState != null)
- return false;
- if (capabilities != null ? !capabilities.equals(host.capabilities) : host.capabilities != null)
- return false;
- if (clusterName != null ? !clusterName.equals(host.clusterName) : host.clusterName != null)
- return false;
- if (clusterType != null ? !clusterType.equals(host.clusterType) : host.clusterType != null)
- return false;
- if (created != null ? !created.equals(host.created) : host.created != null)
- return false;
- if (events != null ? !events.equals(host.events) : host.events != null)
- return false;
- if (hostTags != null ? !hostTags.equals(host.hostTags) : host.hostTags != null)
- return false;
- if (hypervisor != null ? !hypervisor.equals(host.hypervisor) : host.hypervisor != null)
- return false;
- if (ipAddress != null ? !ipAddress.equals(host.ipAddress) : host.ipAddress != null)
- return false;
- if (jobStatus != host.jobStatus) return false;
- if (lastPinged != null ? !lastPinged.equals(host.lastPinged) : host.lastPinged != null)
- return false;
- if (name != null ? !name.equals(host.name) : host.name != null)
- return false;
- if (podName != null ? !podName.equals(host.podName) : host.podName != null)
- return false;
- if (removed != null ? !removed.equals(host.removed) : host.removed != null)
- return false;
- if (state != null ? !state.equals(host.state) : host.state != null)
- return false;
- if (type != null ? !type.equals(host.type) : host.type != null)
- return false;
- if (version != null ? !version.equals(host.version) : host.version != null)
- return false;
- if (zoneName != null ? !zoneName.equals(host.zoneName) : host.zoneName != null)
- return false;
-
- return true;
- }
-
- @Override
public String toString() {
return "Host{" +
"id=" + id +
- ", allocationState='" + allocationState + '\'' +
+ ", allocationState=" + allocationState +
", averageLoad=" + averageLoad +
", capabilities='" + capabilities + '\'' +
", clusterId=" + clusterId +
", clusterName='" + clusterName + '\'' +
- ", clusterType='" + clusterType + '\'' +
- ", cpuAllocated=" + cpuAllocated +
+ ", clusterType=" + clusterType +
+ ", cpuAllocated='" + cpuAllocated + '\'' +
", cpuNumber=" + cpuNumber +
", cpuSpeed=" + cpuSpeed +
- ", cpuUsed=" + cpuUsed +
+ ", cpuUsed='" + cpuUsed + '\'' +
", cpuWithOverProvisioning=" + cpuWithOverProvisioning +
", created=" + created +
", disconnected=" + disconnected +
@@ -864,8 +847,8 @@
", podId=" + podId +
", podName='" + podName + '\'' +
", removed=" + removed +
- ", state='" + state + '\'' +
- ", type='" + type + '\'' +
+ ", state=" + state +
+ ", type=" + type +
", version='" + version + '\'' +
", zoneId=" + zoneId +
", zoneName='" + zoneName + '\'' +
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/DomainDomainAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/DomainDomainAsyncClient.java
new file mode 100644
index 0000000..cbb620b
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/DomainDomainAsyncClient.java
@@ -0,0 +1,83 @@
+/**
+ * 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.features;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.jclouds.cloudstack.domain.Domain;
+import org.jclouds.cloudstack.filters.QuerySigner;
+import org.jclouds.cloudstack.options.ListDomainChildrenOptions;
+import org.jclouds.cloudstack.options.ListDomainsOptions;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.OnlyElement;
+import org.jclouds.rest.annotations.QueryParams;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.SelectJson;
+import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import java.util.Set;
+
+/**
+ * Provides asynchronous access to CloudStack Domain features available to Domain
+ * Admin users.
+ *
+ * @author Andrei Savu
+ * @see <a href=
+ * "http://download.cloud.com/releases/2.2.0/api_2.2.12/TOC_Domain_Admin.html"
+ * />
+ */
+@RequestFilters(QuerySigner.class)
+@QueryParams(keys = "response", values = "json")
+public interface DomainDomainAsyncClient {
+
+ /**
+ * @see DomainDomainClient#listDomains
+ */
+ @GET
+ @QueryParams(keys = "command", values = "listDomains")
+ @SelectJson("domain")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
+ ListenableFuture<Set<Domain>> listDomains(ListDomainsOptions... options);
+
+ /**
+ * @see DomainDomainClient#getDomainById
+ */
+ @GET
+ @QueryParams(keys = "command", values = "listDomains")
+ @SelectJson("domain")
+ @OnlyElement
+ @Consumes(MediaType.APPLICATION_JSON)
+ @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+ ListenableFuture<Domain> getDomainById(@QueryParam("id") long domainId);
+
+ /**
+ * @see DomainDomainClient#listDomainChildren
+ */
+ @GET
+ @QueryParams(keys = "command", values = "listDomainChildren")
+ @SelectJson("domain")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
+ ListenableFuture<Set<Domain>> listDomainChildren(ListDomainChildrenOptions... options);
+}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/DomainDomainClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/DomainDomainClient.java
new file mode 100644
index 0000000..a2ae7ca
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/DomainDomainClient.java
@@ -0,0 +1,70 @@
+/**
+ * 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.features;
+
+import org.jclouds.cloudstack.domain.Domain;
+import org.jclouds.cloudstack.options.ListDomainChildrenOptions;
+import org.jclouds.cloudstack.options.ListDomainsOptions;
+import org.jclouds.concurrent.Timeout;
+
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Provides synchronous access to CloudStack Domain features available to Domain
+ * Admin users.
+ *
+ * @author Andrei Savu
+ * @see <a href=
+ * "http://download.cloud.com/releases/2.2.0/api_2.2.12/TOC_Domain_Admin.html"
+ * />
+ */
+@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
+public interface DomainDomainClient {
+
+ /**
+ * List domains with detailed information
+ *
+ * @param options
+ * list filtering optional arguments
+ * @return
+ * set of domain instances or empty
+ */
+ Set<Domain> listDomains(ListDomainsOptions... options);
+
+ /**
+ * Get a domain by ID
+ *
+ * @param domainId
+ * domain ID
+ * @return
+ * domain instance or null
+ */
+ Domain getDomainById(long domainId);
+
+ /**
+ * Lists all children domains belonging to a specified domain
+ *
+ * @param options
+ * list filtering optional arguments
+ * @return
+ * set of domain instances or empty
+ */
+ Set<Domain> listDomainChildren(ListDomainChildrenOptions... options);
+}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalDomainAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalDomainAsyncClient.java
new file mode 100644
index 0000000..a1bbc82
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalDomainAsyncClient.java
@@ -0,0 +1,87 @@
+/**
+ * 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.features;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.jclouds.cloudstack.domain.Domain;
+import org.jclouds.cloudstack.filters.QuerySigner;
+import org.jclouds.cloudstack.options.CreateDomainOptions;
+import org.jclouds.cloudstack.options.UpdateDomainOptions;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.QueryParams;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.SelectJson;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+
+/**
+ * Provides asynchronous access to CloudStack Domain features available to Global
+ * Admin users.
+ *
+ * @author Andrei Savu
+ * @see <a href=
+ * "http://download.cloud.com/releases/2.2.0/api_2.2.12/TOC_Global_Admin.html"
+ * />
+ */
+@RequestFilters(QuerySigner.class)
+@QueryParams(keys = "response", values = "json")
+public interface GlobalDomainAsyncClient extends DomainDomainAsyncClient {
+
+ /**
+ * @see GlobalDomainClient#createDomain
+ */
+ @GET
+ @QueryParams(keys = "command", values = "createDomain")
+ @SelectJson("domain")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+ ListenableFuture<Domain> createDomain(@QueryParam("name") String name, CreateDomainOptions... options);
+
+ /**
+ * @see GlobalDomainClient#updateDomain
+ */
+ @GET
+ @QueryParams(keys = "command", values = "updateDomain")
+ @SelectJson("domain")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+ ListenableFuture<Domain> updateDomain(@QueryParam("id") long domainId, UpdateDomainOptions... options);
+
+ /**
+ * @see GlobalDomainClient#deleteOnlyDomain
+ */
+ @GET
+ @QueryParams(keys = {"command", "cleanup"}, values = {"deleteDomain", "false"})
+ @ExceptionParser(ReturnVoidOnNotFoundOr404.class)
+ ListenableFuture<Void> deleteOnlyDomain(@QueryParam("id") long id);
+
+ /**
+ * @see GlobalDomainClient#deleteDomainAndAttachedResources
+ */
+ @GET
+ @QueryParams(keys = {"command", "cleanup"}, values = {"deleteDomain", "true"})
+ @ExceptionParser(ReturnVoidOnNotFoundOr404.class)
+ ListenableFuture<Void> deleteDomainAndAttachedResources(@QueryParam("id") long id);
+}
+
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalDomainClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalDomainClient.java
new file mode 100644
index 0000000..9dd9099
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalDomainClient.java
@@ -0,0 +1,79 @@
+/**
+ * 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.features;
+
+import org.jclouds.cloudstack.domain.Domain;
+import org.jclouds.cloudstack.options.CreateDomainOptions;
+import org.jclouds.cloudstack.options.UpdateDomainOptions;
+import org.jclouds.concurrent.Timeout;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Provides synchronous access to CloudStack Domain features available to Global
+ * Admin users.
+ *
+ * @author Andrei Savu
+ * @see <a href=
+ * "http://download.cloud.com/releases/2.2.0/api_2.2.12/TOC_Global_Admin.html"
+ * />
+ */
+@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
+public interface GlobalDomainClient extends DomainDomainClient {
+
+ /**
+ * Create new Domain
+ *
+ * @param name
+ * domain name
+ * @param options
+ * optional arguments
+ * @return
+ * domain instance
+ */
+ Domain createDomain(String name, CreateDomainOptions... options);
+
+ /**
+ * Update a domain
+ *
+ * @param domainId
+ * the ID of the domain
+ * @param options
+ * optional arguments
+ * @return
+ * domain instance
+ */
+ Domain updateDomain(long domainId, UpdateDomainOptions... options);
+
+ /**
+ * Delete domain (without deleting attached resources)
+ *
+ * @param id
+ * the domain ID
+ */
+ Void deleteOnlyDomain(long id);
+
+ /**
+ * Delete domain and cleanup all attached resources
+ *
+ * @param id
+ * the domain ID
+ */
+ Void deleteDomainAndAttachedResources(long id);
+}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java
index a6fc4d0..7085302 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java
@@ -22,8 +22,14 @@
import org.jclouds.cloudstack.domain.Cluster;
import org.jclouds.cloudstack.domain.Host;
import org.jclouds.cloudstack.filters.QuerySigner;
+import org.jclouds.cloudstack.options.AddClusterOptions;
+import org.jclouds.cloudstack.options.AddHostOptions;
+import org.jclouds.cloudstack.options.AddSecondaryStorageOptions;
+import org.jclouds.cloudstack.options.DeleteHostOptions;
import org.jclouds.cloudstack.options.ListClustersOptions;
import org.jclouds.cloudstack.options.ListHostsOptions;
+import org.jclouds.cloudstack.options.UpdateClusterOptions;
+import org.jclouds.cloudstack.options.UpdateHostOptions;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.RequestFilters;
@@ -32,6 +38,7 @@
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
+import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import java.util.Set;
@@ -58,6 +65,108 @@
ListenableFuture<Set<Host>> listHosts(ListHostsOptions... options);
/**
+ * Adds a new host.
+ *
+ * @param zoneId the Zone ID for the host
+ * @param url the host URL
+ * @param hypervisor hypervisor type of the host
+ * @param username the username for the host
+ * @param password the password for the host
+ * @param options optional arguments
+ * @return the new host.
+ */
+ @GET
+ @QueryParams(keys = "command", values = "addHost")
+ @SelectJson("host")
+ @Consumes(MediaType.APPLICATION_JSON)
+ ListenableFuture<Host> addHost(@QueryParam("zoneid") long zoneId, @QueryParam("url") String url, @QueryParam("hypervisor") String hypervisor, @QueryParam("username") String username, @QueryParam("password") String password, AddHostOptions... options);
+
+ /**
+ * Updates a host.
+ *
+ * @param hostId the ID of the host to update
+ * @param options optional arguments
+ * @return the modified host.
+ */
+ @GET
+ @QueryParams(keys = "command", values = "updateHost")
+ @SelectJson("host")
+ @Consumes(MediaType.APPLICATION_JSON)
+ ListenableFuture<Host> updateHost(@QueryParam("id") long hostId, UpdateHostOptions... options);
+
+ /**
+ * Update password of a host on management server.
+ *
+ * @param hostId the host ID
+ * @param username the username for the host
+ * @param password the password for the host
+ */
+ @GET
+ @QueryParams(keys = "command", values = "updateHostPassword")
+ @Consumes(MediaType.APPLICATION_JSON)
+ ListenableFuture<Void> updateHostPassword(@QueryParam("hostid") long hostId, @QueryParam("username") String username, @QueryParam("password") String password);
+
+ /**
+ * Deletes a host.
+ *
+ * @param hostId the host ID
+ * @param options optional arguments
+ */
+ @GET
+ @QueryParams(keys = "command", values = "deleteHost")
+ @Consumes(MediaType.APPLICATION_JSON)
+ ListenableFuture<Void> deleteHost(@QueryParam("id") long hostId, DeleteHostOptions... options);
+
+ /**
+ * Prepares a host for maintenance.
+ *
+ * @param hostId the host ID
+ * @return a job reference number for tracking this asynchronous job.
+ */
+ @GET
+ @QueryParams(keys = "command", values = "prepareHostForMaintenance")
+ @SelectJson("jobid")
+ @Consumes(MediaType.APPLICATION_JSON)
+ ListenableFuture<Long> prepareHostForMaintenance(@QueryParam("id") long hostId);
+
+ /**
+ * Cancels host maintenance.
+ *
+ * @param hostId the host ID
+ * @return a job reference number for tracking this asynchronous job.
+ */
+ @GET
+ @QueryParams(keys = "command", values = "cancelHostMaintenance")
+ @SelectJson("jobid")
+ @Consumes(MediaType.APPLICATION_JSON)
+ ListenableFuture<Long> cancelHostMaintenance(@QueryParam("id") long hostId);
+
+ /**
+ * Reconnects a host.
+ *
+ * @param hostId
+ * @return a job reference number for tracking this asynchronous job.
+ */
+ @GET
+ @QueryParams(keys = "command", values = "reconnectHost")
+ @SelectJson("jobid")
+ @Consumes(MediaType.APPLICATION_JSON)
+ ListenableFuture<Long> reconnectHost(@QueryParam("id") long hostId);
+
+ /**
+ * Adds secondary storage.
+ *
+ * @param url the URL for the secondary storage
+ * @param options optional arguments
+ * @return the host of the storage.
+ */
+ @GET
+ @QueryParams(keys = "command", values = "addSecondaryStorage")
+ @SelectJson("host")
+ @Consumes(MediaType.APPLICATION_JSON)
+ ListenableFuture<Host> addSecondaryStorage(@QueryParam("url") String url, AddSecondaryStorageOptions... options);
+
+ /**
* @see GlobalHostClient#listClusters
*/
@GET
@@ -66,4 +175,57 @@
@Consumes(MediaType.APPLICATION_JSON)
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<Cluster>> listClusters(ListClustersOptions... options);
+
+ /**
+ * Adds a new cluster.
+ *
+ * @param zoneId the Zone ID for the cluster
+ * @param clusterName the cluster name
+ * @param clusterType type of the cluster
+ * @param hypervisor hypervisor type of the cluster
+ * @param options optional arguments
+ * @return the new cluster.
+ */
+ @GET
+ @QueryParams(keys = "command", values = "addCluster")
+ @SelectJson("cluster")
+ @Consumes(MediaType.APPLICATION_JSON)
+ ListenableFuture<Cluster> addCluster(@QueryParam("zoneid") long zoneId, @QueryParam("clustername") String clusterName, @QueryParam("clustertype") Host.ClusterType clusterType, @QueryParam("hypervisor") String hypervisor, AddClusterOptions... options);
+
+ /**
+ * Updates an existing cluster.
+ *
+ * @param clusterId the ID of the cluster
+ * @param options optional arguments
+ * @return the modified cluster
+ */
+ @GET
+ @QueryParams(keys = "command", values = "updateCluster")
+ @SelectJson("cluster")
+ @Consumes(MediaType.APPLICATION_JSON)
+ ListenableFuture<Cluster> updateCluster(@QueryParam("id") long clusterId, UpdateClusterOptions... options);
+
+ /**
+ * Update password of a cluster on management server.
+ *
+ * @param clusterId the cluster ID
+ * @param username the username for the cluster
+ * @param password the password for the cluster
+ */
+ @GET
+ @QueryParams(keys = "command", values = "updateHostPassword")
+ @SelectJson("cluster")
+ @Consumes(MediaType.APPLICATION_JSON)
+ ListenableFuture<Void> updateClusterPassword(@QueryParam("clusterid") long clusterId, @QueryParam("username") String username, @QueryParam("password") String password);
+
+ /**
+ * Deletes a cluster.
+ *
+ * @param clusterId the cluster ID
+ */
+ @GET
+ @QueryParams(keys = "command", values = "deleteCluster")
+ @Consumes(MediaType.APPLICATION_JSON)
+ ListenableFuture<Void> deleteCluster(@QueryParam("id") long clusterId);
+
}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java
index 414ce8b..7345263 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java
@@ -20,8 +20,14 @@
import org.jclouds.cloudstack.domain.Cluster;
import org.jclouds.cloudstack.domain.Host;
+import org.jclouds.cloudstack.options.AddClusterOptions;
+import org.jclouds.cloudstack.options.AddHostOptions;
+import org.jclouds.cloudstack.options.AddSecondaryStorageOptions;
+import org.jclouds.cloudstack.options.DeleteHostOptions;
import org.jclouds.cloudstack.options.ListClustersOptions;
import org.jclouds.cloudstack.options.ListHostsOptions;
+import org.jclouds.cloudstack.options.UpdateClusterOptions;
+import org.jclouds.cloudstack.options.UpdateHostOptions;
import org.jclouds.concurrent.Timeout;
import java.util.Set;
@@ -49,10 +55,120 @@
Set<Host> listHosts(ListHostsOptions... options);
/**
+ * Adds a new host.
+ *
+ * @param zoneId the Zone ID for the host
+ * @param url the host URL
+ * @param hypervisor hypervisor type of the host
+ * @param username the username for the host
+ * @param password the password for the host
+ * @param options optional arguments
+ * @return the new host.
+ */
+ Host addHost(long zoneId, String url, String hypervisor, String username, String password, AddHostOptions... options);
+
+ /**
+ * Updates a host.
+ *
+ * @param hostId the ID of the host to update
+ * @param options optional arguments
+ * @return the modified host.
+ */
+ Host updateHost(long hostId, UpdateHostOptions... options);
+
+ /**
+ * Update password of a host on management server.
+ *
+ * @param hostId the host ID
+ * @param username the username for the host
+ * @param password the password for the host
+ */
+ void updateHostPassword(long hostId, String username, String password);
+
+ /**
+ * Deletes a host.
+ *
+ * @param hostId the host ID
+ * @param options optional arguments
+ */
+ void deleteHost(long hostId, DeleteHostOptions... options);
+
+ /**
+ * Prepares a host for maintenance.
+ *
+ * @param hostId the host ID
+ * @return a job reference number for tracking this asynchronous job.
+ */
+ Long prepareHostForMaintenance(long hostId);
+
+ /**
+ * Cancels host maintenance.
+ *
+ * @param hostId the host ID
+ * @return a job reference number for tracking this asynchronous job.
+ */
+ Long cancelHostMaintenance(long hostId);
+
+ /**
+ * Reconnects a host.
+ *
+ * @param hostId
+ * @return a job reference number for tracking this asynchronous job.
+ */
+ Long reconnectHost(long hostId);
+
+ /**
+ * Adds secondary storage.
+ *
+ * @param url the URL for the secondary storage
+ * @param options optional arguments
+ * @return the host of the storage.
+ */
+ Host addSecondaryStorage(String url, AddSecondaryStorageOptions... options);
+
+ /**
* Lists clusters
*
* @param options if present, how to constrain the list
* @return clusters matching query, or empty set if no clusters match
*/
Set<Cluster> listClusters(ListClustersOptions... options);
+
+ /**
+ * Adds a new cluster.
+ *
+ * @param zoneId the Zone ID for the cluster
+ * @param clusterName the cluster name
+ * @param clusterType type of the cluster
+ * @param hypervisor hypervisor type of the cluster
+ * @param options optional arguments
+ * @return the new cluster.
+ */
+ Cluster addCluster(long zoneId, String clusterName, Host.ClusterType clusterType, String hypervisor, AddClusterOptions... options);
+
+ /**
+ * Updates an existing cluster.
+ *
+ * @param clusterId the ID of the cluster
+ * @param options optional arguments
+ * @return the modified cluster
+ */
+ Cluster updateCluster(long clusterId, UpdateClusterOptions... options);
+
+ /**
+ * Update password of a cluster on management server.
+ *
+ * @param hostId the cluster ID
+ * @param username the username for the cluster
+ * @param password the password for the cluster
+ */
+ void updateClusterPassword(long clusterId, String username, String password);
+
+ /**
+ * Deletes a cluster.
+ *
+ * @param clusterId the cluster ID
+ */
+ void deleteCluster(long clusterId);
+
}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/AddClusterOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/AddClusterOptions.java
new file mode 100644
index 0000000..107a6a8
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/AddClusterOptions.java
@@ -0,0 +1,115 @@
+/**
+ * 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.options;
+
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.cloudstack.domain.Host;
+import org.jclouds.functions.JoinOnComma;
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+import java.util.Set;
+
+/**
+ * Options to the GlobalHostClient.addHost() API call
+ *
+ * @author Richard Downer
+ */
+public class AddClusterOptions extends BaseHttpRequestOptions {
+
+ public static final AddClusterOptions NONE = new AddClusterOptions();
+
+ /**
+ * @param allocationState Allocation state of this Host for allocation of new resources
+ */
+ public AddClusterOptions allocationState(Host.AllocationState allocationState) {
+ this.queryParameters.replaceValues("allocationstate", ImmutableSet.of(allocationState.toString()));
+ return this;
+ }
+
+ /**
+ * @param password the password for the host
+ */
+ public AddClusterOptions password(String password) {
+ this.queryParameters.replaceValues("password", ImmutableSet.of(password));
+ return this;
+ }
+
+ /**
+ * @param podId the Pod ID for the host
+ */
+ public AddClusterOptions podId(long podId) {
+ this.queryParameters.replaceValues("podid", ImmutableSet.of(podId + ""));
+ return this;
+ }
+
+ /**
+ * @param url the URL
+ */
+ public AddClusterOptions url(String url) {
+ this.queryParameters.replaceValues("url", ImmutableSet.of(url));
+ return this;
+ }
+
+ /**
+ * @param username the username for the cluster
+ */
+ public AddClusterOptions username(String username) {
+ this.queryParameters.replaceValues("username", ImmutableSet.of(username));
+ return this;
+ }
+
+ public static class Builder {
+
+ /**
+ * @param allocationState Allocation state of this Host for allocation of new resources
+ */
+ public static AddClusterOptions allocationState(Host.AllocationState allocationState) {
+ return new AddClusterOptions().allocationState(allocationState);
+ }
+
+ /**
+ * @param password the password for the host
+ */
+ public static AddClusterOptions password(String password) {
+ return new AddClusterOptions().password(password);
+ }
+
+ /**
+ * @param podId the Pod ID for the host
+ */
+ public static AddClusterOptions podId(long podId) {
+ return new AddClusterOptions().podId(podId);
+ }
+
+ /**
+ * @param url the URL
+ */
+ public static AddClusterOptions url(String url) {
+ return new AddClusterOptions().url(url);
+ }
+
+ /**
+ * @param username the username for the cluster
+ */
+ public static AddClusterOptions username(String username) {
+ return new AddClusterOptions().username(username);
+ }
+
+ }
+}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/AddHostOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/AddHostOptions.java
new file mode 100644
index 0000000..5cdf4bb
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/AddHostOptions.java
@@ -0,0 +1,115 @@
+/**
+ * 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.options;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.cloudstack.domain.Host;
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+import java.util.Set;
+
+/**
+ * Options to the GlobalHostClient.addHost() API call
+ *
+ * @author Richard Downer
+ */
+public class AddHostOptions extends BaseHttpRequestOptions {
+
+ public static final AddHostOptions NONE = new AddHostOptions();
+
+ /**
+ * @param allocationState Allocation state of this Host for allocation of new resources
+ */
+ public AddHostOptions allocationState(Host.AllocationState allocationState) {
+ this.queryParameters.replaceValues("allocationstate", ImmutableSet.of(allocationState.toString()));
+ return this;
+ }
+
+ /**
+ * @param clusterId the cluster ID for the host
+ */
+ public AddHostOptions clusterId(long clusterId) {
+ this.queryParameters.replaceValues("clusterid", ImmutableSet.of(clusterId + ""));
+ return this;
+ }
+
+ /**
+ * @param clusterName the cluster name for the host
+ */
+ public AddHostOptions clusterName(String clusterName) {
+ this.queryParameters.replaceValues("clustername", ImmutableSet.of(clusterName));
+ return this;
+ }
+
+ /**
+ * @param hostTags list of tags to be added to the host
+ */
+ public AddHostOptions hostTags(Set<String> hostTags) {
+ this.queryParameters.replaceValues("hosttags", ImmutableSet.of(Joiner.on(',').join(hostTags)));
+ return this;
+ }
+
+ /**
+ * @param podId the Pod ID for the host
+ */
+ public AddHostOptions podId(long podId) {
+ this.queryParameters.replaceValues("podid", ImmutableSet.of(podId + ""));
+ return this;
+ }
+
+ public static class Builder {
+
+ /**
+ * @param allocationState Allocation state of this Host for allocation of new resources
+ */
+ public static AddHostOptions allocationState(Host.AllocationState allocationState) {
+ return new AddHostOptions().allocationState(allocationState);
+ }
+
+ /**
+ * @param clusterId the cluster ID for the host
+ */
+ public static AddHostOptions clusterId(long clusterId) {
+ return new AddHostOptions().clusterId(clusterId);
+ }
+
+ /**
+ * @param clusterName the cluster name for the host
+ */
+ public static AddHostOptions clusterName(String clusterName) {
+ return new AddHostOptions().clusterName(clusterName);
+ }
+
+ /**
+ * @param hostTags list of tags to be added to the host
+ */
+ public static AddHostOptions hostTags(Set<String> hostTags) {
+ return new AddHostOptions().hostTags(hostTags);
+ }
+
+ /**
+ * @param podId the Pod ID for the host
+ */
+ public static AddHostOptions podId(long podId) {
+ return new AddHostOptions().podId(podId);
+ }
+
+ }
+}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/AddSecondaryStorageOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/AddSecondaryStorageOptions.java
new file mode 100644
index 0000000..cfe8d5b
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/AddSecondaryStorageOptions.java
@@ -0,0 +1,53 @@
+/**
+ * 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.options;
+
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Options for the GlobalHostClient.addSecondaryStorage() API call
+ *
+ * @author Richard Downer
+ */
+public class AddSecondaryStorageOptions extends BaseHttpRequestOptions {
+
+ public static final AddSecondaryStorageOptions NONE = new AddSecondaryStorageOptions();
+
+ /**
+ * @param zoneId
+ * the ID of the zone
+ */
+ public AddSecondaryStorageOptions zoneId(long zoneId) {
+ this.queryParameters.replaceValues("zoneid", ImmutableSet.of(zoneId + ""));
+ return this;
+ }
+
+ public static class Builder {
+
+ /**
+ * @param zoneId
+ * the ID of the zone
+ */
+ public static AddSecondaryStorageOptions zoneId(long zoneId) {
+ return new AddSecondaryStorageOptions().zoneId(zoneId);
+ }
+
+ }
+}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/CreateDomainOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/CreateDomainOptions.java
new file mode 100644
index 0000000..9012402
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/CreateDomainOptions.java
@@ -0,0 +1,75 @@
+/**
+ * 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.options;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+import java.util.Set;
+
+/**
+ * Options used to control how a domain is created
+ *
+ * @see <a href=
+ * "http://download.cloud.com/releases/2.2.0/api_2.2.12/global_admin/createDomain.html"
+ * />
+ * @author Andrei Savu
+ */
+public class CreateDomainOptions extends BaseHttpRequestOptions {
+
+ public static final CreateDomainOptions NONE = new CreateDomainOptions();
+
+ /**
+ * @param networkDomain
+ * network domain for networks in the domain
+ */
+ public CreateDomainOptions networkDomain(String networkDomain) {
+ this.queryParameters.replaceValues("networkdomain", ImmutableSet.of(networkDomain));
+ return this;
+ }
+
+ /**
+ * @param parentDomainId
+ * the ID of the parent domain
+ */
+ public CreateDomainOptions parentDomainId(long parentDomainId) {
+ this.queryParameters.replaceValues("parentdomainid", ImmutableSet.of(parentDomainId + ""));
+ return this;
+ }
+
+ public static class Builder {
+
+ /**
+ * @see CreateDomainOptions#networkDomain
+ */
+ public static CreateDomainOptions networkDomain(String networkDomain) {
+ CreateDomainOptions options = new CreateDomainOptions();
+ return options.networkDomain(networkDomain);
+ }
+
+ /**
+ * @see CreateDomainOptions#parentDomainId
+ */
+ public static CreateDomainOptions parentDomainId(long parentDomainId) {
+ CreateDomainOptions options = new CreateDomainOptions();
+ return options.parentDomainId(parentDomainId);
+ }
+ }
+}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/DeleteHostOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/DeleteHostOptions.java
new file mode 100644
index 0000000..f8d3a12
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/DeleteHostOptions.java
@@ -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.options;
+
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Options to the GlobalHostClient.deleteHost() API call
+ *
+ * @author Richard Downer
+ */
+public class DeleteHostOptions extends BaseHttpRequestOptions {
+
+ public static final DeleteHostOptions NONE = new DeleteHostOptions();
+
+ /**
+ * @param forced Force delete the host. All HA enabled vms running on the host will be put to HA; HA disabled ones will be stopped
+ */
+ public DeleteHostOptions forced(boolean forced) {
+ this.queryParameters.replaceValues("forced", ImmutableSet.of(forced + ""));
+ return this;
+ }
+
+ /**
+ * @param forceDestroyLocalStorage Force destroy local storage on this host. All VMs created on this local storage will be destroyed
+ */
+ public DeleteHostOptions forceDestroyLocalStorage(boolean forceDestroyLocalStorage) {
+ this.queryParameters.replaceValues("forcedestroylocalstorage", ImmutableSet.of(forceDestroyLocalStorage + ""));
+ return this;
+ }
+
+ public static class Builder {
+
+ /**
+ * @param forced Force delete the host. All HA enabled vms running on the host will be put to HA; HA disabled ones will be stopped
+ */
+ public static DeleteHostOptions forced(boolean forced) {
+ return new DeleteHostOptions().forced(forced);
+ }
+
+ /**
+ * @param forceDestroyLocalStorage Force destroy local storage on this host. All VMs created on this local storage will be destroyed
+ */
+ public static DeleteHostOptions forceDestroyLocalStorage(boolean forceDestroyLocalStorage) {
+ return new DeleteHostOptions().forceDestroyLocalStorage(forceDestroyLocalStorage);
+ }
+
+ }
+}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListDomainChildrenOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListDomainChildrenOptions.java
new file mode 100644
index 0000000..1adcea6
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListDomainChildrenOptions.java
@@ -0,0 +1,133 @@
+/**
+ * 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.options;
+
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Options used to control what domain children are returned
+ *
+ * @see <a href=
+ * "http://download.cloud.com/releases/2.2.0/api_2.2.12/domain_admin/listDomains.html"
+ * />
+ * @author Andrei Savu
+ */
+public class ListDomainChildrenOptions extends BaseHttpRequestOptions {
+
+ public static final ListDomainChildrenOptions NONE = new ListDomainChildrenOptions();
+
+ /**
+ * @param parentDomainId
+ * firewall rule ID
+ */
+ public ListDomainChildrenOptions parentDomainId(long parentDomainId) {
+ this.queryParameters.replaceValues("id", ImmutableSet.of(parentDomainId + ""));
+ return this;
+ }
+
+ /**
+ * @param isRecursive
+ * to return the entire tree, use the value "true". To return
+ * the first level children, use the value "false".
+ */
+ public ListDomainChildrenOptions isRecursive(boolean isRecursive) {
+ this.queryParameters.replaceValues("isrecursive", ImmutableSet.of(isRecursive + ""));
+ return this;
+ }
+
+ /**
+ * @param keyword
+ * list by keyword
+ */
+ public ListDomainChildrenOptions keyword(String keyword) {
+ this.queryParameters.replaceValues("keyword", ImmutableSet.of(keyword));
+ return this;
+ }
+
+ /**
+ * @param name
+ * list by domain name
+ */
+ public ListDomainChildrenOptions name(String name) {
+ this.queryParameters.replaceValues("name", ImmutableSet.of(name));
+ return this;
+ }
+
+ public ListDomainChildrenOptions page(long page) {
+ this.queryParameters.replaceValues("page", ImmutableSet.of(page + ""));
+ return this;
+ }
+
+ public ListDomainChildrenOptions pageSize(long pageSize) {
+ this.queryParameters.replaceValues("pagesize", ImmutableSet.of(pageSize + ""));
+ return this;
+ }
+
+ public static class Builder {
+
+ /**
+ * @see ListDomainChildrenOptions#parentDomainId
+ */
+ public static ListDomainChildrenOptions parentDomainId(long parentDomainId) {
+ ListDomainChildrenOptions options = new ListDomainChildrenOptions();
+ return options.parentDomainId(parentDomainId);
+ }
+
+ /**
+ * @see ListDomainChildrenOptions#isRecursive
+ */
+ public static ListDomainChildrenOptions isRecursive(boolean isRecursive) {
+ ListDomainChildrenOptions options = new ListDomainChildrenOptions();
+ return options.isRecursive(isRecursive);
+ }
+
+ /**
+ * @see ListDomainChildrenOptions#keyword
+ */
+ public static ListDomainChildrenOptions keyword(String keyword) {
+ ListDomainChildrenOptions options = new ListDomainChildrenOptions();
+ return options.keyword(keyword);
+ }
+
+ /**
+ * @see ListDomainChildrenOptions#name
+ */
+ public static ListDomainChildrenOptions name(String name) {
+ ListDomainChildrenOptions options = new ListDomainChildrenOptions();
+ return options.name(name);
+ }
+
+ /**
+ * @see ListDomainChildrenOptions#page
+ */
+ public static ListDomainChildrenOptions page(long page) {
+ ListDomainChildrenOptions options = new ListDomainChildrenOptions();
+ return options.page(page);
+ }
+
+ /**
+ * @see ListDomainChildrenOptions#pageSize
+ */
+ public static ListDomainChildrenOptions pageSize(long pageSize) {
+ ListDomainChildrenOptions options = new ListDomainChildrenOptions();
+ return options.pageSize(pageSize);
+ }
+ }
+}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListDomainsOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListDomainsOptions.java
new file mode 100644
index 0000000..3b987df
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListDomainsOptions.java
@@ -0,0 +1,132 @@
+/**
+ * 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.options;
+
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Options used to control what domains are returned
+ *
+ * @see <a href=
+ * "http://download.cloud.com/releases/2.2.0/api_2.2.12/domain_admin/listDomains.html"
+ * />
+ * @author Andrei Savu
+ */
+public class ListDomainsOptions extends BaseHttpRequestOptions {
+
+ public static final ListDomainsOptions NONE = new ListDomainsOptions();
+
+ /**
+ * @param id
+ * firewall rule ID
+ */
+ public ListDomainsOptions id(long id) {
+ this.queryParameters.replaceValues("id", ImmutableSet.of(id + ""));
+ return this;
+ }
+
+ /**
+ * @param keyword
+ * list by keyword
+ */
+ public ListDomainsOptions keyword(String keyword) {
+ this.queryParameters.replaceValues("keyword", ImmutableSet.of(keyword));
+ return this;
+ }
+
+ /**
+ * @param level
+ * list by domain level
+ */
+ public ListDomainsOptions level(long level) {
+ this.queryParameters.replaceValues("level", ImmutableSet.of(level + ""));
+ return this;
+ }
+
+ /**
+ * @param name
+ * list by domain name
+ */
+ public ListDomainsOptions name(String name) {
+ this.queryParameters.replaceValues("name", ImmutableSet.of(name));
+ return this;
+ }
+
+ public ListDomainsOptions page(long page) {
+ this.queryParameters.replaceValues("page", ImmutableSet.of(page + ""));
+ return this;
+ }
+
+ public ListDomainsOptions pageSize(long pageSize) {
+ this.queryParameters.replaceValues("pagesize", ImmutableSet.of(pageSize + ""));
+ return this;
+ }
+
+ public static class Builder {
+
+ /**
+ * @see ListDomainsOptions#id
+ */
+ public static ListDomainsOptions id(long id) {
+ ListDomainsOptions options = new ListDomainsOptions();
+ return options.id(id);
+ }
+
+ /**
+ * @see ListDomainsOptions#keyword
+ */
+ public static ListDomainsOptions keyword(String keyword) {
+ ListDomainsOptions options = new ListDomainsOptions();
+ return options.keyword(keyword);
+ }
+
+ /**
+ * @see ListDomainsOptions#level
+ */
+ public static ListDomainsOptions level(long level) {
+ ListDomainsOptions options = new ListDomainsOptions();
+ return options.level(level);
+ }
+
+ /**
+ * @see ListDomainsOptions#name
+ */
+ public static ListDomainsOptions name(String name) {
+ ListDomainsOptions options = new ListDomainsOptions();
+ return options.name(name);
+ }
+
+ /**
+ * @see ListDomainsOptions#page
+ */
+ public static ListDomainsOptions page(long page) {
+ ListDomainsOptions options = new ListDomainsOptions();
+ return options.page(page);
+ }
+
+ /**
+ * @see ListDomainsOptions#pageSize
+ */
+ public static ListDomainsOptions pageSize(long pageSize) {
+ ListDomainsOptions options = new ListDomainsOptions();
+ return options.pageSize(pageSize);
+ }
+ }
+}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/UpdateClusterOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/UpdateClusterOptions.java
new file mode 100644
index 0000000..e02fcbd
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/UpdateClusterOptions.java
@@ -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.options;
+
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.cloudstack.domain.Cluster;
+import org.jclouds.cloudstack.domain.Host;
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Options for the GlobalHostClient.updateCluster() API call.
+ *
+ * @author Richard Downer
+ */
+public class UpdateClusterOptions extends BaseHttpRequestOptions {
+
+ public static final UpdateClusterOptions NONE = new UpdateClusterOptions();
+
+ /**
+ * @param allocationState Allocation state of this cluster for allocation of new resources
+ */
+ public UpdateClusterOptions allocationState(Host.AllocationState allocationState) {
+ this.queryParameters.replaceValues("allocationstate", ImmutableSet.<String>of(allocationState.toString()));
+ return this;
+ }
+
+ /**
+ * @param clusterName the cluster name
+ */
+ public UpdateClusterOptions clusterName(String clusterName) {
+ this.queryParameters.replaceValues("clustername", ImmutableSet.<String>of(clusterName));
+ return this;
+ }
+
+ /**
+ * @param clusterType type of the cluster
+ */
+ public UpdateClusterOptions clusterType(Host.ClusterType clusterType) {
+ this.queryParameters.replaceValues("clustertype", ImmutableSet.<String>of(clusterType.toString()));
+ return this;
+ }
+
+ /**
+ * @param hypervisor hypervisor type of the cluster
+ */
+ public UpdateClusterOptions hypervisor(String hypervisor) {
+ this.queryParameters.replaceValues("hypervisor", ImmutableSet.<String>of(hypervisor));
+ return this;
+ }
+
+ /**
+ * @param managedState whether this cluster is managed by cloudstack
+ */
+ public UpdateClusterOptions managedState(Cluster.ManagedState managedState) {
+ this.queryParameters.replaceValues("managedstate", ImmutableSet.<String>of(managedState.toString()));
+ return this;
+ }
+
+ public static class Builder {
+
+ /**
+ * @param allocationState Allocation state of this cluster for allocation of new resources
+ */
+ public static UpdateClusterOptions allocationState(Host.AllocationState allocationState) {
+ return new UpdateClusterOptions().allocationState(allocationState);
+ }
+
+ /**
+ * @param clusterName the cluster name
+ */
+ public static UpdateClusterOptions clusterName(String clusterName) {
+ return new UpdateClusterOptions().clusterName(clusterName);
+ }
+
+ /**
+ * @param clusterType type of the cluster
+ */
+ public static UpdateClusterOptions clusterType(Host.ClusterType clusterType) {
+ return new UpdateClusterOptions().clusterType(clusterType);
+ }
+
+ /**
+ * @param hypervisor hypervisor type of the cluster
+ */
+ public static UpdateClusterOptions hypervisor(String hypervisor) {
+ return new UpdateClusterOptions().hypervisor(hypervisor);
+ }
+
+ /**
+ * @param managedState whether this cluster is managed by cloudstack
+ */
+ public static UpdateClusterOptions managedState(Cluster.ManagedState managedState) {
+ return new UpdateClusterOptions().managedState(managedState);
+ }
+
+ }
+}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/UpdateDomainOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/UpdateDomainOptions.java
new file mode 100644
index 0000000..d7d972f
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/UpdateDomainOptions.java
@@ -0,0 +1,72 @@
+/**
+ * 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.options;
+
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Options used to control how a domain is created
+ *
+ * @see <a href=
+ * "http://download.cloud.com/releases/2.2.0/api_2.2.12/global_admin/createDomain.html"
+ * />
+ * @author Andrei Savu
+ */
+public class UpdateDomainOptions extends BaseHttpRequestOptions {
+
+ public static final UpdateDomainOptions NONE = new UpdateDomainOptions();
+
+ /**
+ * @param name
+ * the new name for this domain
+ */
+ public UpdateDomainOptions name(String name) {
+ this.queryParameters.replaceValues("name", ImmutableSet.of(name));
+ return this;
+ }
+
+ /**
+ * @param networkDomain
+ * network domain for networks in the domain
+ */
+ public UpdateDomainOptions networkDomain(String networkDomain) {
+ this.queryParameters.replaceValues("networkdomain", ImmutableSet.of(networkDomain));
+ return this;
+ }
+
+ public static class Builder {
+
+ /**
+ * @see UpdateDomainOptions#name
+ */
+ public static UpdateDomainOptions name(String name) {
+ UpdateDomainOptions options = new UpdateDomainOptions();
+ return options.name(name);
+ }
+
+ /**
+ * @see UpdateDomainOptions#networkDomain
+ */
+ public static UpdateDomainOptions networkDomain(String networkDomain) {
+ UpdateDomainOptions options = new UpdateDomainOptions();
+ return options.networkDomain(networkDomain);
+ }
+ }
+}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/UpdateHostOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/UpdateHostOptions.java
new file mode 100644
index 0000000..e89013a
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/UpdateHostOptions.java
@@ -0,0 +1,87 @@
+/**
+ * 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.options;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.cloudstack.domain.Host;
+import org.jclouds.functions.JoinOnComma;
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+import java.util.Set;
+
+/**
+ * Options to the GlobalHostClient.addHost() API call
+ *
+ * @author Richard Downer
+ */
+public class UpdateHostOptions extends BaseHttpRequestOptions {
+
+
+ public static final UpdateHostOptions NONE = new UpdateHostOptions();
+
+ /**
+ * @param allocationState Allocation state of this Host for allocation of new resources
+ */
+ public UpdateHostOptions allocationState(Host.AllocationState allocationState) {
+ this.queryParameters.replaceValues("allocationstate", ImmutableSet.of(allocationState.toString()));
+ return this;
+ }
+
+ /**
+ * @param hostTags list of tags to be added to the host
+ */
+ public UpdateHostOptions hostTags(Set<String> hostTags) {
+ this.queryParameters.replaceValues("hosttags", ImmutableSet.of(Joiner.on(',').join(hostTags)));
+ return this;
+ }
+
+ /**
+ * @param osCategoryId the id of Os category to update the host with
+ */
+ public UpdateHostOptions osCategoryId(long osCategoryId) {
+ this.queryParameters.replaceValues("oscategoryid", ImmutableSet.of(osCategoryId + ""));
+ return this;
+ }
+
+ public static class Builder {
+
+ /**
+ * @param allocationState Allocation state of this Host for allocation of new resources
+ */
+ public static UpdateHostOptions allocationState(Host.AllocationState allocationState) {
+ return new UpdateHostOptions().allocationState(allocationState);
+ }
+
+ /**
+ * @param hostTags list of tags to be added to the host
+ */
+ public static UpdateHostOptions hostTags(Set<String> hostTags) {
+ return new UpdateHostOptions().hostTags(hostTags);
+ }
+
+ /**
+ * @param podId the Pod ID for the host
+ */
+ public static UpdateHostOptions osCategoryId(long osCategoryId) {
+ return new UpdateHostOptions().osCategoryId(osCategoryId);
+ }
+
+ }
+}
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/DomainDomainClientExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/DomainDomainClientExpectTest.java
new file mode 100644
index 0000000..f47d03e
--- /dev/null
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/DomainDomainClientExpectTest.java
@@ -0,0 +1,182 @@
+/**
+ * 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.features;
+
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.cloudstack.CloudStackContext;
+import org.jclouds.cloudstack.domain.Account;
+import org.jclouds.cloudstack.domain.Domain;
+import org.jclouds.cloudstack.domain.User;
+import org.jclouds.cloudstack.options.ListDomainChildrenOptions;
+import org.jclouds.date.internal.SimpleDateFormatDateService;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.testng.annotations.Test;
+
+import java.net.URI;
+import java.util.Set;
+
+import static org.jclouds.cloudstack.options.ListDomainChildrenOptions.Builder.parentDomainId;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+
+/**
+ * Test the CloudStack DomainDomainClient
+ *
+ * @author Andrei Savu
+ */
+@Test(groups = "unit", testName = "DomainDomainClientExpectTest")
+public class DomainDomainClientExpectTest extends BaseCloudStackRestClientExpectTest<DomainDomainClient> {
+
+ public void testListDomainsWhenResponseIs2xx() {
+ DomainDomainClient client = requestSendsResponse(
+ HttpRequest.builder()
+ .method("GET")
+ .endpoint(
+ URI.create("http://localhost:8080/client/api?response=json&" +
+ "command=listDomains&apiKey=identity&signature=MmzRB%2FpKlYyWy7kE3IMXrg4BUtk%3D"))
+ .headers(
+ ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .build())
+ .build(),
+ HttpResponse.builder()
+ .statusCode(200)
+ .payload(payloadFromResource("/listdomainsresponse.json"))
+ .build());
+
+ assertEquals(client.listDomains(),
+ ImmutableSet.of(
+ Domain.builder().id(1L).name("ROOT").level(0).hasChild(true).build(),
+ Domain.builder().id(2L).name("jclouds1").level(1).parentDomainId(1)
+ .parentDomainName("ROOT").hasChild(false).build()
+ ));
+ }
+
+ public void testListDomainsWhenResponseIs404() {
+ DomainDomainClient client = requestSendsResponse(
+ HttpRequest.builder()
+ .method("GET")
+ .endpoint(
+ URI.create("http://localhost:8080/client/api?response=json&" +
+ "command=listDomains&apiKey=identity&signature=MmzRB%2FpKlYyWy7kE3IMXrg4BUtk%3D"))
+ .headers(
+ ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .build())
+ .build(),
+ HttpResponse.builder()
+ .statusCode(404)
+ .build());
+
+ assertEquals(client.listDomains(), ImmutableSet.of());
+ }
+
+ public void testGetDomainWhenResponseIs2xx() {
+ DomainDomainClient client = requestSendsResponse(
+ HttpRequest.builder()
+ .method("GET")
+ .endpoint(
+ URI.create("http://localhost:8080/client/api?response=json&" +
+ "command=listDomains&id=1&apiKey=identity&signature=emQKWkVhospRkaUzjKljME2rW0k%3D"))
+ .headers(
+ ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .build())
+ .build(),
+ HttpResponse.builder()
+ .statusCode(200)
+ .payload(payloadFromResource("/getdomainresponse.json"))
+ .build());
+
+ assertEquals(client.getDomainById(1),
+ Domain.builder().id(1L).name("ROOT").level(0).hasChild(true).build());
+ }
+
+ public void testGetDomainWhenResponseIs404() {
+ DomainDomainClient client = requestSendsResponse(
+ HttpRequest.builder()
+ .method("GET")
+ .endpoint(
+ URI.create("http://localhost:8080/client/api?response=json&" +
+ "command=listDomains&id=1&apiKey=identity&signature=emQKWkVhospRkaUzjKljME2rW0k%3D"))
+ .headers(
+ ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .build())
+ .build(),
+ HttpResponse.builder()
+ .statusCode(404)
+ .build());
+
+ assertNull(client.getDomainById(1));
+ }
+
+ public void testListDomainChildrenWhenResponseIs2xx() {
+ DomainDomainClient client = requestSendsResponse(
+ HttpRequest.builder()
+ .method("GET")
+ .endpoint(
+ URI.create("http://localhost:8080/client/api?response=json&" +
+ "command=listDomainChildren&id=1&isrecursive=true&apiKey=identity&signature=bDMSkjme8k0ANUPm4YiTYKe2N88%3D"))
+ .headers(
+ ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .build())
+ .build(),
+ HttpResponse.builder()
+ .statusCode(200)
+ .payload(payloadFromResource("/listdomainchildrenresponse.json"))
+ .build());
+
+ assertEquals(client.listDomainChildren(parentDomainId(1).isRecursive(true)),
+ ImmutableSet.of(
+ Domain.builder().id(2L).name("jclouds1").level(1).parentDomainId(1)
+ .parentDomainName("ROOT").hasChild(false).build(),
+ Domain.builder().id(3L).name("jclouds2").level(1).parentDomainId(1)
+ .parentDomainName("ROOT").hasChild(false).build()
+ ));
+ }
+
+ public void testListDomainChildrenWhenResponseIs404() {
+ DomainDomainClient client = requestSendsResponse(
+ HttpRequest.builder()
+ .method("GET")
+ .endpoint(
+ URI.create("http://localhost:8080/client/api?response=json&" +
+ "command=listDomainChildren&id=1&isrecursive=true&apiKey=identity&" +
+ "signature=bDMSkjme8k0ANUPm4YiTYKe2N88%3D"))
+ .headers(
+ ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .build())
+ .build(),
+ HttpResponse.builder()
+ .statusCode(404)
+ .build());
+
+ assertEquals(client.listDomainChildren(parentDomainId(1).isRecursive(true)), ImmutableSet.of());
+ }
+
+ @Override
+ protected DomainDomainClient clientFrom(CloudStackContext context) {
+ return context.getDomainContext().getApi().getDomainClient();
+ }
+}
\ No newline at end of file
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/DomainDomainClientLiveTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/DomainDomainClientLiveTest.java
new file mode 100644
index 0000000..553a563
--- /dev/null
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/DomainDomainClientLiveTest.java
@@ -0,0 +1,95 @@
+/**
+ * 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.features;
+
+import com.google.common.base.Predicate;
+import org.jclouds.cloudstack.domain.Domain;
+import org.testng.annotations.Test;
+
+import javax.annotation.Nullable;
+import java.util.Set;
+
+import static com.google.common.collect.Iterables.find;
+import static org.jclouds.cloudstack.options.ListDomainChildrenOptions.Builder.parentDomainId;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Tests behavior of {@code DomainDomainClient}
+ *
+ * @author Andrei Savu
+ */
+@Test(groups = "live", singleThreaded = true, testName = "DomainDomainClientLiveTest")
+public class DomainDomainClientLiveTest extends BaseCloudStackClientLiveTest {
+
+ @Test
+ public void testListDomains() {
+ assert domainAdminEnabled;
+
+ Set<Domain> allDomains = domainAdminClient.getDomainClient().listDomains();
+
+ Domain root = find(allDomains, withName("ROOT"));
+ assertEquals(root, domainAdminClient.getDomainClient().getDomainById(root.getId()));
+ assertEquals(root.getLevel(), 0);
+ assertEquals(root.getParentDomainId(), 0);
+ assertNull(root.getParentDomainName());
+ if (allDomains.size() > 0) {
+ assertTrue(root.hasChild());
+ }
+
+ for (Domain domain : allDomains) {
+ checkDomain(domain, allDomains);
+ }
+ }
+
+ @Test
+ public void testListDomainChildren() {
+ assert domainAdminEnabled;
+
+ Set<Domain> allDomains = domainAdminClient.getDomainClient().listDomains();
+ Domain root = find(allDomains, withName("ROOT"));
+
+ Set<Domain> children = domainAdminClient.getDomainClient()
+ .listDomainChildren(parentDomainId(root.getId()).isRecursive(true));
+ assertEquals(allDomains.size() - 1, children.size());
+
+ for (Domain domain : children) {
+ checkDomain(domain, allDomains);
+ }
+ }
+
+ private Predicate<Domain> withName(final String name) {
+ return new Predicate<Domain>() {
+ @Override
+ public boolean apply(@Nullable Domain domain) {
+ return domain != null && domain.getName().equals(name);
+ }
+ };
+ }
+
+ private void checkDomain(Domain domain, Set<Domain> allDomains) {
+ assert domain.getId() > 0 : domain;
+ if (domain.getParentDomainName() != null) {
+ Domain parent = find(allDomains, withName(domain.getParentDomainName()));
+ assertEquals(parent.getId(), domain.getParentDomainId());
+ assertTrue(parent.hasChild());
+ }
+ }
+}
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalDomainClientExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalDomainClientExpectTest.java
new file mode 100644
index 0000000..4b3ecb8
--- /dev/null
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalDomainClientExpectTest.java
@@ -0,0 +1,163 @@
+/**
+ * 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.features;
+
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.cloudstack.CloudStackContext;
+import org.jclouds.cloudstack.domain.Domain;
+import org.jclouds.cloudstack.options.UpdateDomainOptions;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.testng.annotations.Test;
+
+import java.net.URI;
+
+import static org.jclouds.cloudstack.options.ListDomainChildrenOptions.Builder.parentDomainId;
+import static org.jclouds.cloudstack.options.UpdateDomainOptions.Builder.name;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+
+/**
+ * Test the CloudStack GlobalDomainClient
+ *
+ * @author Andrei Savu
+ */
+@Test(groups = "unit", testName = "GlobalDomainClientExpectTest")
+public class GlobalDomainClientExpectTest extends BaseCloudStackRestClientExpectTest<GlobalDomainClient> {
+
+ public void testCreateDomainWhenResponseIs2xx() {
+ GlobalDomainClient client = requestSendsResponse(
+ HttpRequest.builder()
+ .method("GET")
+ .endpoint(
+ URI.create("http://localhost:8080/client/api?response=json&command=createDomain&" +
+ "name=test&apiKey=identity&signature=6cxzEo7h63G0hgTTMLm4lGsSDK8%3D"))
+ .headers(
+ ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .build())
+ .build(),
+ HttpResponse.builder()
+ .statusCode(200)
+ .payload(payloadFromResource("/createdomainresponse.json"))
+ .build());
+
+ assertEquals(client.createDomain("test"),
+ Domain.builder().id(10L).name("test").level(1).parentDomainId(1L)
+ .parentDomainName("ROOT").hasChild(false).build());
+ }
+
+ public void testCreateDomainWhenResponseIs404() {
+ GlobalDomainClient client = requestSendsResponse(
+ HttpRequest.builder()
+ .method("GET")
+ .endpoint(
+ URI.create("http://localhost:8080/client/api?response=json&command=createDomain&" +
+ "name=test&apiKey=identity&signature=6cxzEo7h63G0hgTTMLm4lGsSDK8%3D"))
+ .headers(
+ ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .build())
+ .build(),
+ HttpResponse.builder()
+ .statusCode(404)
+ .build());
+
+ assertNull(client.createDomain("test"));
+ }
+
+ public void testUpdateDomainWhenResponseIs2xx() {
+ GlobalDomainClient client = requestSendsResponse(
+ HttpRequest.builder()
+ .method("GET")
+ .endpoint(
+ URI.create("http://localhost:8080/client/api?response=json&" +
+ "command=updateDomain&id=10&name=test-2&apiKey=identity&signature=5t1eUf2Eyf%2FaB6qt%2BqIj%2BmcwFIo%3D"))
+ .headers(
+ ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .build())
+ .build(),
+ HttpResponse.builder()
+ .statusCode(200)
+ .payload(payloadFromResource("/updatedomainresponse.json"))
+ .build());
+
+ assertEquals(client.updateDomain(10, name("test-2")),
+ Domain.builder().id(10L).name("test-2").level(1).parentDomainId(1L)
+ .parentDomainName("ROOT").hasChild(false).build());
+ }
+
+ public void testUpdateDomainWhenResponseIs404() {
+ GlobalDomainClient client = requestSendsResponse(
+ HttpRequest.builder()
+ .method("GET")
+ .endpoint(
+ URI.create("http://localhost:8080/client/api?response=json&" +
+ "command=updateDomain&id=10&name=test-2&apiKey=identity&signature=5t1eUf2Eyf%2FaB6qt%2BqIj%2BmcwFIo%3D"))
+ .headers(
+ ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .build())
+ .build(),
+ HttpResponse.builder()
+ .statusCode(404)
+ .build());
+
+ assertNull(client.updateDomain(10, name("test-2")));
+ }
+
+ public void testDeleteOnlyDomain() {
+ GlobalDomainClient client = requestSendsResponse(
+ HttpRequest.builder()
+ .method("GET")
+ .endpoint(
+ URI.create("http://localhost:8080/client/api?response=json&" +
+ "command=deleteDomain&cleanup=false&id=1&apiKey=identity&signature=%2F5aLbigg612t9IrZi0JZO7CyiOU%3D"))
+ .build(),
+ HttpResponse.builder()
+ .statusCode(200)
+ .payload(payloadFromResource("/deletedomainresponse.json"))
+ .build());
+
+ client.deleteOnlyDomain(1);
+ }
+
+ public void testDeleteDomainAndAttachedResources() {
+ GlobalDomainClient client = requestSendsResponse(
+ HttpRequest.builder()
+ .method("GET")
+ .endpoint(
+ URI.create("http://localhost:8080/client/api?response=json&" +
+ "command=deleteDomain&cleanup=true&id=1&apiKey=identity&signature=grL7JStvtYUT89Jr0D8FgwMyJpU%3D"))
+ .build(),
+ HttpResponse.builder()
+ .statusCode(200)
+ .payload(payloadFromResource("/deletedomainresponse.json"))
+ .build());
+
+ client.deleteDomainAndAttachedResources(1);
+ }
+
+ @Override
+ protected GlobalDomainClient clientFrom(CloudStackContext context) {
+ return context.getGlobalContext().getApi().getDomainClient();
+ }
+}
\ No newline at end of file
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalDomainClientLiveTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalDomainClientLiveTest.java
new file mode 100644
index 0000000..d585ebe
--- /dev/null
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalDomainClientLiveTest.java
@@ -0,0 +1,81 @@
+/**
+ * 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.features;
+
+import com.google.common.base.Predicate;
+import org.jclouds.cloudstack.domain.Domain;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import javax.annotation.Nullable;
+
+import static com.google.common.collect.Iterables.find;
+import static org.jclouds.cloudstack.options.UpdateDomainOptions.Builder.name;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+
+/**
+ * Tests behavior of {@code GlobalDomainClient}
+ *
+ * @author Andrei Savu
+ */
+@Test(groups = "live", singleThreaded = true, testName = "GlobalDomainClientLiveTest")
+public class GlobalDomainClientLiveTest extends BaseCloudStackClientLiveTest {
+
+ private GlobalDomainClient domainClient;
+ private Domain rootDomain;
+
+ @BeforeMethod
+ public void before() {
+ domainClient = globalAdminClient.getDomainClient();
+ rootDomain = find(domainClient.listDomains(), new Predicate<Domain>() {
+ @Override
+ public boolean apply(@Nullable Domain domain) {
+ return domain != null && domain.getName().equals("ROOT");
+ }
+ });
+ }
+
+ @Test
+ public void testCreateUpdateDeleteDomain() {
+ assert globalAdminEnabled;
+
+ Domain domain = null;
+ try {
+ domain = domainClient.createDomain(prefix + "-domain");
+ checkDomain(domain, rootDomain, prefix + "-domain");
+
+ Domain updated = domainClient.updateDomain(domain.getId(), name(prefix + "-domain-2"));
+ checkDomain(updated, rootDomain, prefix + "-domain-2");
+ assertEquals(updated.getId(), domain.getId());
+
+ } finally {
+ if (domain != null) {
+ domainClient.deleteDomainAndAttachedResources(domain.getId());
+ }
+ }
+ assertNull(domainClient.getDomainById(domain.getId()));
+ }
+
+ private void checkDomain(Domain domain, Domain rootDomain, String expectedName) {
+ assertEquals(domain.getParentDomainId(), rootDomain.getId());
+ assertEquals(domain.getName(), expectedName);
+ assertEquals(domain.getParentDomainName(), rootDomain.getName());
+ }
+}
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java
new file mode 100644
index 0000000..616b135
--- /dev/null
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java
@@ -0,0 +1,348 @@
+/**
+ * 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.features;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.cloudstack.CloudStackContext;
+import org.jclouds.cloudstack.domain.Cluster;
+import org.jclouds.cloudstack.domain.ConfigurationEntry;
+import org.jclouds.cloudstack.domain.Host;
+import org.jclouds.cloudstack.options.AddClusterOptions;
+import org.jclouds.cloudstack.options.AddHostOptions;
+import org.jclouds.cloudstack.options.AddSecondaryStorageOptions;
+import org.jclouds.cloudstack.options.DeleteHostOptions;
+import org.jclouds.cloudstack.options.UpdateClusterOptions;
+import org.jclouds.cloudstack.options.UpdateHostOptions;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.testng.annotations.Test;
+
+import java.net.URI;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Set;
+import java.util.TimeZone;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+
+/**
+ * Test the CloudStack GlobalHostClient
+ *
+ * @author Richard Downer
+ */
+@Test(groups = "unit", testName = "GlobalConfigurationClientExpectTest")
+public class GlobalHostClientExpectTest extends BaseCloudStackRestClientExpectTest<GlobalHostClient> {
+
+ @Test
+ public void testListHostsWhenResponseIs2xx() {
+ HttpRequest request = HttpRequest.builder()
+ .method("GET")
+ .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=listHosts&apiKey=identity&signature=wsv4UBgXxURW0pNlso4MT9E052s%3D"))
+ .headers(ImmutableMultimap.<String, String>builder().put("Accept", "application/json").build())
+ .build();
+ HttpResponse response = HttpResponse.builder()
+ .payload(payloadFromResource("/listhostsresponse.json"))
+ .statusCode(200).build();
+
+ Set<Host> actual = requestSendsResponse(request, response).listHosts();
+
+ Date lastPinged = makeDate(1970, Calendar.JANUARY, 16, 0, 54, 43, "UTC");
+ Date created = makeDate(2011, Calendar.NOVEMBER, 26, 23, 28, 36, "UTC");
+ Host host1 = Host.builder().id(1).name("cs2-xevsrv.alucloud.local").state(Host.State.UP).type(Host.Type.ROUTING).ipAddress("10.26.26.107").zoneId(1).zoneName("Dev Zone 1").podId(1).podName("Dev Pod 1").version("2.2.12.20110928142833").hypervisor("XenServer").cpuNumber(24).cpuSpeed(2266).cpuAllocated("2.76%").cpuUsed("0.1%").cpuWithOverProvisioning(54384.0F).networkKbsRead(4443).networkKbsWrite(15048).memoryTotal(100549733760L).memoryAllocated(3623878656L).memoryUsed(3623878656L).capabilities("xen-3.0-x86_64 , xen-3.0-x86_32p , hvm-3.0-x86_32 , hvm-3.0-x86_32p , hvm-3.0-x86_64").lastPinged(lastPinged).managementServerId(223098941760041L).clusterId(1).clusterName("Xen Clust 1").clusterType(Host.ClusterType.CLOUD_MANAGED).localStorageActive(false).created(created).events("PrepareUnmanaged; HypervisorVersionChanged; ManagementServerDown; PingTimeout; AgentDisconnected; MaintenanceRequested; HostDown; AgentConnected; StartAgentRebalance; ShutdownRequested; Ping").hostTags("").hasEnoughCapacity(false).allocationState(Host.AllocationState.ENABLED).build();
+
+ Date disconnected = makeDate(2011, Calendar.NOVEMBER, 26, 23, 33, 38, "UTC");
+ lastPinged = makeDate(1970, Calendar.JANUARY, 16, 0, 42, 30, "UTC");
+ created = makeDate(2011, Calendar.NOVEMBER, 26, 23, 33, 38, "UTC");
+ Host host2 = Host.builder().id(2).name("nfs://10.26.26.165/mnt/nfs/cs_sec").state(Host.State.ALERT).disconnected(disconnected).type(Host.Type.SECONDARY_STORAGE).ipAddress("nfs").zoneId(1).zoneName("Dev Zone 1").version("2.2.12.20110928142833").hypervisor("None").lastPinged(lastPinged).localStorageActive(false).created(created).events("ManagementServerDown; AgentDisconnected; Remove; MaintenanceRequested; AgentConnected; Ping").hasEnoughCapacity(false).allocationState(Host.AllocationState.ENABLED).build();
+
+ lastPinged = makeDate(1970, Calendar.JANUARY, 16, 0, 54, 43, "UTC");
+ created = makeDate(2011, Calendar.NOVEMBER, 26, 23, 35, 51, "UTC");
+ Host host3 = Host.builder().id(3).name("s-1-VM").state(Host.State.UP).type(Host.Type.SECONDARY_STORAGE_VM).ipAddress("10.26.26.81").zoneId(1).zoneName("Dev Zone 1").podId(1).podName("Dev Pod 1").version("2.2.12.20110928142833").lastPinged(lastPinged).managementServerId(223098941760041L).localStorageActive(false).created(created).events("PrepareUnmanaged; HypervisorVersionChanged; ManagementServerDown; PingTimeout; AgentDisconnected; MaintenanceRequested; HostDown; AgentConnected; StartAgentRebalance; ShutdownRequested; Ping").hasEnoughCapacity(false).allocationState(Host.AllocationState.ENABLED).build();
+
+ lastPinged = makeDate(1970, Calendar.JANUARY, 16, 0, 54, 43, "UTC");
+ created = makeDate(2011, Calendar.NOVEMBER, 26, 23, 36, 46, "UTC");
+ Host host4 = Host.builder().id(4).name("v-2-VM").state(Host.State.UP).type(Host.Type.CONSOLE_PROXY).ipAddress("10.26.26.96").zoneId(1).zoneName("Dev Zone 1").podId(1).podName("Dev Pod 1").version("2.2.12.20110928142833").lastPinged(lastPinged).managementServerId(223098941760041L).localStorageActive(false).created(created).events("PrepareUnmanaged; HypervisorVersionChanged; ManagementServerDown; PingTimeout; AgentDisconnected; MaintenanceRequested; HostDown; AgentConnected; StartAgentRebalance; ShutdownRequested; Ping").hasEnoughCapacity(false).allocationState(Host.AllocationState.ENABLED).build();
+
+ Set<Host> expected = ImmutableSet.of(host1, host2, host3, host4);
+
+ assertEquals(actual, expected);
+ }
+
+ @Test
+ public void testListHostsEmptyOn404() {
+ HttpRequest request = HttpRequest.builder()
+ .method("GET")
+ .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=listHosts&apiKey=identity&signature=wsv4UBgXxURW0pNlso4MT9E052s%3D"))
+ .headers(ImmutableMultimap.<String, String>builder().put("Accept", "application/json").build())
+ .build();
+ HttpResponse response = HttpResponse.builder().statusCode(404).build();
+ GlobalHostClient client = requestSendsResponse(request, response);
+
+ assertEquals(client.listHosts(), ImmutableSet.of());
+ }
+
+ @Test
+ public void testAddHostWhenResponseIs2xx() {
+ HttpRequest request = HttpRequest.builder()
+ .method("GET")
+ .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=addHost&zoneid=1&hypervisor=XenServer&url=http%3A%2F%2Fexample.com&username=fred&password=sekrit&hosttags=&allocationstate=Enabled&clusterid=1&clustername=Xen%20Clust%201&podid=1&apiKey=identity&signature=ExGaljKKQIlVbWk5hd0BnnjmBzs%3D"))
+ .headers(ImmutableMultimap.<String, String>builder().put("Accept", "application/json").build())
+ .build();
+ HttpResponse response = HttpResponse.builder()
+ .payload(payloadFromResource("/addhostresponse.json"))
+ .statusCode(200).build();
+
+ Date lastPinged = makeDate(1970, Calendar.JANUARY, 16, 0, 54, 43, "UTC");
+ Date created = makeDate(2011, Calendar.NOVEMBER, 26, 23, 28, 36, "UTC");
+ Host expected = Host.builder().id(1).name("cs2-xevsrv.alucloud.local").state(Host.State.UP).type(Host.Type.ROUTING).ipAddress("10.26.26.107").zoneId(1).zoneName("Dev Zone 1").podId(1).podName("Dev Pod 1").version("2.2.12.20110928142833").hypervisor("XenServer").cpuNumber(24).cpuSpeed(2266).cpuAllocated("2.76%").cpuUsed("0.1%").cpuWithOverProvisioning(54384.0F).networkKbsRead(4443).networkKbsWrite(15048).memoryTotal(100549733760L).memoryAllocated(3623878656L).memoryUsed(3623878656L).capabilities("xen-3.0-x86_64 , xen-3.0-x86_32p , hvm-3.0-x86_32 , hvm-3.0-x86_32p , hvm-3.0-x86_64").lastPinged(lastPinged).managementServerId(223098941760041L).clusterId(1).clusterName("Xen Clust 1").clusterType(Host.ClusterType.CLOUD_MANAGED).localStorageActive(false).created(created).events("PrepareUnmanaged; HypervisorVersionChanged; ManagementServerDown; PingTimeout; AgentDisconnected; MaintenanceRequested; HostDown; AgentConnected; StartAgentRebalance; ShutdownRequested; Ping").hostTags("").hasEnoughCapacity(false).allocationState(Host.AllocationState.ENABLED).build();
+
+ Host actual = requestSendsResponse(request, response).addHost(1, "http://example.com", "XenServer", "fred", "sekrit",
+ AddHostOptions.Builder.hostTags(Collections.<String>emptySet()).allocationState(Host.AllocationState.ENABLED).clusterId(1).clusterName("Xen Clust 1").podId(1));
+
+ assertEquals(actual, expected);
+ }
+
+ @Test
+ public void testUpdateHostWhenResponseIs2xx() {
+ HttpRequest request = HttpRequest.builder()
+ .method("GET")
+ .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=updateHost&id=1&allocationstate=Enabled&hosttags=&oscategoryid=5&apiKey=identity&signature=qTxNq9yQG8S108giqS%2FROFzgev8%3D"))
+ .headers(ImmutableMultimap.<String, String>builder().put("Accept", "application/json").build())
+ .build();
+ HttpResponse response = HttpResponse.builder()
+ .payload(payloadFromResource("/updatehostresponse.json"))
+ .statusCode(200).build();
+
+ Date lastPinged = makeDate(1970, Calendar.JANUARY, 16, 0, 54, 43, "UTC");
+ Date created = makeDate(2011, Calendar.NOVEMBER, 26, 23, 28, 36, "UTC");
+ Host expected = Host.builder().id(1).name("cs2-xevsrv.alucloud.local").state(Host.State.UP).type(Host.Type.ROUTING).ipAddress("10.26.26.107").zoneId(1).zoneName("Dev Zone 1").podId(1).podName("Dev Pod 1").version("2.2.12.20110928142833").hypervisor("XenServer").cpuNumber(24).cpuSpeed(2266).cpuAllocated("2.76%").cpuUsed("0.1%").cpuWithOverProvisioning(54384.0F).networkKbsRead(4443).networkKbsWrite(15048).memoryTotal(100549733760L).memoryAllocated(3623878656L).memoryUsed(3623878656L).capabilities("xen-3.0-x86_64 , xen-3.0-x86_32p , hvm-3.0-x86_32 , hvm-3.0-x86_32p , hvm-3.0-x86_64").lastPinged(lastPinged).managementServerId(223098941760041L).clusterId(1).clusterName("Xen Clust 1").clusterType(Host.ClusterType.CLOUD_MANAGED).localStorageActive(false).created(created).events("PrepareUnmanaged; HypervisorVersionChanged; ManagementServerDown; PingTimeout; AgentDisconnected; MaintenanceRequested; HostDown; AgentConnected; StartAgentRebalance; ShutdownRequested; Ping").hostTags("").hasEnoughCapacity(false).allocationState(Host.AllocationState.ENABLED).build();
+
+ Host actual = requestSendsResponse(request, response).updateHost(1, UpdateHostOptions.Builder.allocationState(Host.AllocationState.ENABLED).hostTags(Collections.<String>emptySet()).osCategoryId(5));
+
+ assertEquals(actual, expected);
+ }
+
+ @Test
+ public void testUpdateHostPasswordWhenResponseIs2xx() {
+ HttpRequest request = HttpRequest.builder()
+ .method("GET")
+ .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=updateHostPassword&hostid=1&password=sekrit&username=fred&apiKey=identity&signature=g9nMKDWoiU72y0HhaRFekZCgfJc%3D"))
+ .headers(ImmutableMultimap.<String, String>builder().put("Accept", "application/json").build())
+ .build();
+ HttpResponse response = HttpResponse.builder()
+ .statusCode(200).build();
+
+ requestSendsResponse(request, response).updateHostPassword(1, "fred", "sekrit");
+ }
+
+ @Test
+ public void testDeleteHostWhenResponseIs2xx() {
+ HttpRequest request = HttpRequest.builder()
+ .method("GET")
+ .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=deleteHost&id=1&forced=true&forcedestroylocalstorage=true&apiKey=identity&signature=ZdvO1BWBkdPiDAjsVlKtqDe6N7k%3D"))
+ .headers(ImmutableMultimap.<String, String>builder().put("Accept", "application/json").build())
+ .build();
+ HttpResponse response = HttpResponse.builder()
+ .statusCode(200).build();
+
+ requestSendsResponse(request, response).deleteHost(1, DeleteHostOptions.Builder.forced(true).forceDestroyLocalStorage(true));
+ }
+
+ @Test
+ public void testPrepareHostForMaintenanceWhenResponseIs2xx() {
+ HttpRequest request = HttpRequest.builder()
+ .method("GET")
+ .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=prepareHostForMaintenance&id=1&apiKey=identity&signature=9tDwdox%2FxAKmZr9kVrR6Ttnxf3U%3D"))
+ .headers(ImmutableMultimap.<String, String>builder().put("Accept", "application/json").build())
+ .build();
+ HttpResponse response = HttpResponse.builder()
+ .payload(payloadFromResource("/preparehostformaintenanceresponse.json"))
+ .statusCode(200).build();
+
+ Long actual = requestSendsResponse(request, response).prepareHostForMaintenance(1);
+ assertEquals(actual, Long.valueOf(2036L));
+ }
+
+ @Test
+ public void testCancelHostMaintenanceWhenResponseIs2xx() {
+ HttpRequest request = HttpRequest.builder()
+ .method("GET")
+ .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=cancelHostMaintenance&id=1&apiKey=identity&signature=9RduzuBoyRZKNTzAoVqUo9gRTfk%3D"))
+ .headers(ImmutableMultimap.<String, String>builder().put("Accept", "application/json").build())
+ .build();
+ HttpResponse response = HttpResponse.builder()
+ .payload(payloadFromResource("/cancelhostmaintenanceresponse.json"))
+ .statusCode(200).build();
+
+ Long actual = requestSendsResponse(request, response).cancelHostMaintenance(1);
+ assertEquals(actual, Long.valueOf(2036L));
+ }
+
+ @Test
+ public void testReconnectHostWhenResponseIs2xx() {
+ HttpRequest request = HttpRequest.builder()
+ .method("GET")
+ .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=reconnectHost&id=1&apiKey=identity&signature=wJEF02vwdyOnJOTa%2BWMMK906aRU%3D"))
+ .headers(ImmutableMultimap.<String, String>builder().put("Accept", "application/json").build())
+ .build();
+ HttpResponse response = HttpResponse.builder()
+ .payload(payloadFromResource("/reconnecthostresponse.json"))
+ .statusCode(200).build();
+
+ Long actual = requestSendsResponse(request, response).reconnectHost(1);
+ assertEquals(actual, Long.valueOf(2036L));
+ }
+
+ @Test
+ public void testAddSecondaryStorageWhenResponseIs2xx() {
+ HttpRequest request = HttpRequest.builder()
+ .method("GET")
+ .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=addSecondaryStorage&url=nfs%3A%2F%2F10.26.26.165%2Fmnt%2Fnfs%2Fcs_sec&zoneid=1&apiKey=identity&signature=MccRKx1yPP43ImiO70WlhVDlAIA%3D"))
+ .headers(ImmutableMultimap.<String, String>builder().put("Accept", "application/json").build())
+ .build();
+ HttpResponse response = HttpResponse.builder()
+ .payload(payloadFromResource("/addsecondarystorageresponse.json"))
+ .statusCode(200).build();
+
+ Date disconnected = makeDate(2011, Calendar.NOVEMBER, 26, 23, 33, 38, "UTC");
+ Date lastPinged = makeDate(1970, Calendar.JANUARY, 16, 0, 42, 30, "UTC");
+ Date created = makeDate(2011, Calendar.NOVEMBER, 26, 23, 33, 38, "UTC");
+ Host expected = Host.builder().id(2).name("nfs://10.26.26.165/mnt/nfs/cs_sec").state(Host.State.ALERT).disconnected(disconnected).type(Host.Type.SECONDARY_STORAGE).ipAddress("nfs").zoneId(1).zoneName("Dev Zone 1").version("2.2.12.20110928142833").hypervisor("None").lastPinged(lastPinged).localStorageActive(false).created(created).events("ManagementServerDown; AgentDisconnected; Remove; MaintenanceRequested; AgentConnected; Ping").hasEnoughCapacity(false).allocationState(Host.AllocationState.ENABLED).build();
+
+ Host actual = requestSendsResponse(request, response).addSecondaryStorage("nfs://10.26.26.165/mnt/nfs/cs_sec", AddSecondaryStorageOptions.Builder.zoneId(1));
+
+ assertEquals(actual, expected);
+ }
+
+ @Test
+ public void testListClustersWhenResponseIs2xx() {
+ HttpRequest request = HttpRequest.builder()
+ .method("GET")
+ .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=listClusters&apiKey=identity&signature=MWOOe7bm1J14DIfLjAGqsSVb8oo%3D"))
+ .headers(ImmutableMultimap.<String, String>builder().put("Accept", "application/json").build())
+ .build();
+ HttpResponse response = HttpResponse.builder()
+ .payload(payloadFromResource("/listclustersresponse.json"))
+ .statusCode(200).build();
+
+ Set<Cluster> actual = requestSendsResponse(request, response).listClusters();
+
+ Cluster cluster1 = Cluster.builder().id(1).name("Xen Clust 1").podId(1).podName("Dev Pod 1").zoneId(1).zoneName("Dev Zone 1").hypervisor("XenServer").clusterType(Host.ClusterType.CLOUD_MANAGED).allocationState(Host.AllocationState.ENABLED).managedState(Cluster.ManagedState.MANAGED).build();
+ Cluster cluster2 = Cluster.builder().id(2).name("Xen Clust 1").podId(2).podName("Dev Pod 2").zoneId(2).zoneName("Dev Zone 2").hypervisor("XenServer").clusterType(Host.ClusterType.CLOUD_MANAGED).allocationState(Host.AllocationState.ENABLED).managedState(Cluster.ManagedState.MANAGED).build();
+ ImmutableSet<Cluster> expected = ImmutableSet.of(cluster1, cluster2);
+
+ assertEquals(actual, expected);
+ }
+
+ @Test
+ public void testListClustersEmptyOn404() {
+ HttpRequest request = HttpRequest.builder()
+ .method("GET")
+ .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=listClusters&apiKey=identity&signature=MWOOe7bm1J14DIfLjAGqsSVb8oo%3D"))
+ .headers(ImmutableMultimap.<String, String>builder().put("Accept", "application/json").build())
+ .build();
+ HttpResponse response = HttpResponse.builder().statusCode(404).build();
+ GlobalHostClient client = requestSendsResponse(request, response);
+
+ assertEquals(client.listClusters(), ImmutableSet.of());
+ }
+
+ @Test
+ public void testAddClusterWhenResponseIs2xx() {
+ HttpRequest request = HttpRequest.builder()
+ .method("GET")
+ .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=addCluster&zoneid=1&clustertype=CloudManaged&clustername=Xen%20Clust%201&hypervisor=XenServer&allocationstate=Enabled&podid=1&url=http%3A%2F%2Fexample.com%2Fcluster&username=fred&password=sekrit&apiKey=identity&signature=2uIQ5qF0bVycXK111wxvogWp1Yw%3D"))
+ .headers(ImmutableMultimap.<String, String>builder().put("Accept", "application/json").build())
+ .build();
+ HttpResponse response = HttpResponse.builder()
+ .payload(payloadFromResource("/addclusterresponse.json"))
+ .statusCode(200).build();
+
+ Cluster expected = Cluster.builder().id(1).name("Xen Clust 1").podId(1).podName("Dev Pod 1").zoneId(1).zoneName("Dev Zone 1").hypervisor("XenServer").clusterType(Host.ClusterType.CLOUD_MANAGED).allocationState(Host.AllocationState.ENABLED).managedState(Cluster.ManagedState.MANAGED).build();
+
+ Cluster actual = requestSendsResponse(request, response).addCluster(1, "Xen Clust 1", Host.ClusterType.CLOUD_MANAGED, "XenServer", AddClusterOptions.Builder.allocationState(Host.AllocationState.ENABLED).podId(1).url("http://example.com/cluster").username("fred").password("sekrit"));
+
+ assertEquals(actual, expected);
+ }
+
+ @Test
+ public void testUpdateClusterWhenResponseIs2xx() {
+ HttpRequest request = HttpRequest.builder()
+ .method("GET")
+ .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=updateCluster&id=1&allocationstate=Enabled&clustername=Xen%20Clust%201&clustertype=CloudManaged&hypervisor=XenServer&managedstate=Managed&apiKey=identity&signature=%2FwbuYKwInciSXWkUf05lEfJZShQ%3D"))
+ .headers(ImmutableMultimap.<String, String>builder().put("Accept", "application/json").build())
+ .build();
+ HttpResponse response = HttpResponse.builder()
+ .payload(payloadFromResource("/updateclusterresponse.json"))
+ .statusCode(200).build();
+
+ Cluster expected = Cluster.builder().id(1).name("Xen Clust 1").podId(1).podName("Dev Pod 1").zoneId(1).zoneName("Dev Zone 1").hypervisor("XenServer").clusterType(Host.ClusterType.CLOUD_MANAGED).allocationState(Host.AllocationState.ENABLED).managedState(Cluster.ManagedState.MANAGED).build();
+
+ Cluster actual = requestSendsResponse(request, response).updateCluster(1, UpdateClusterOptions.Builder.allocationState(Host.AllocationState.ENABLED).clusterName("Xen Clust 1").clusterType(Host.ClusterType.CLOUD_MANAGED).hypervisor("XenServer").managedState(Cluster.ManagedState.MANAGED));
+
+ assertEquals(actual, expected);
+ }
+
+ @Test
+ public void testUpdateClusterPasswordWhenResponseIs2xx() {
+ HttpRequest request = HttpRequest.builder()
+ .method("GET")
+ .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=updateHostPassword&clusterid=1&password=sekrit&username=fred&apiKey=identity&signature=xwc83%2BoYK0cuAiFQAlg%2F7%2F1IVHE%3D"))
+ .headers(ImmutableMultimap.<String, String>builder().put("Accept", "application/json").build())
+ .build();
+ HttpResponse response = HttpResponse.builder()
+ .statusCode(200).build();
+
+ requestSendsResponse(request, response).updateClusterPassword(1, "fred", "sekrit");
+ }
+
+ @Test
+ public void testDeleteClusterWhenResponseIs2xx() {
+ HttpRequest request = HttpRequest.builder()
+ .method("GET")
+ .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=deleteCluster&id=1&apiKey=identity&signature=CKH26MFgKGY7Sosd17LjBMNa3AI%3D"))
+ .headers(ImmutableMultimap.<String, String>builder().put("Accept", "application/json").build())
+ .build();
+ HttpResponse response = HttpResponse.builder()
+ .statusCode(200).build();
+
+ requestSendsResponse(request, response).deleteCluster(1);
+ }
+
+ private Date makeDate(int year, int month, int date, int hour, int minute, int second, String timeZoneName) {
+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(timeZoneName));
+ cal.set(Calendar.YEAR, year);
+ cal.set(Calendar.MONTH, month);
+ cal.set(Calendar.DATE, date);
+ cal.set(Calendar.HOUR_OF_DAY, hour);
+ cal.set(Calendar.MINUTE, minute);
+ cal.set(Calendar.SECOND, second);
+ cal.set(Calendar.MILLISECOND, 0);
+ return cal.getTime();
+ }
+
+ @Override
+ protected GlobalHostClient clientFrom(CloudStackContext context) {
+ return context.getGlobalContext().getApi().getHostClient();
+ }
+}
\ No newline at end of file
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/AddClusterOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/AddClusterOptionsTest.java
new file mode 100644
index 0000000..333343e
--- /dev/null
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/AddClusterOptionsTest.java
@@ -0,0 +1,86 @@
+/**
+ * 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.options;
+
+import com.google.common.collect.ImmutableList;
+import org.jclouds.cloudstack.domain.Host;
+import org.testng.annotations.Test;
+
+import static org.jclouds.cloudstack.options.AddClusterOptions.Builder.*;
+import static org.testng.Assert.assertEquals;
+
+/**
+ * Tests behavior of {@code AddClusterOptions}
+ *
+ * @author Richard Downer
+ */
+@Test(groups = "unit")
+public class AddClusterOptionsTest {
+
+ public void testAllocationState() {
+ AddClusterOptions options = new AddClusterOptions().allocationState(Host.AllocationState.ENABLED);
+ assertEquals(ImmutableList.of("Enabled"), options.buildQueryParameters().get("allocationstate"));
+ }
+
+ public void testAllocationStateStatic() {
+ AddClusterOptions options = allocationState(Host.AllocationState.ENABLED);
+ assertEquals(ImmutableList.of("Enabled"), options.buildQueryParameters().get("allocationstate"));
+ }
+
+ public void testPassword() {
+ AddClusterOptions options = new AddClusterOptions().password("sekrit");
+ assertEquals(ImmutableList.of("sekrit"), options.buildQueryParameters().get("password"));
+ }
+
+ public void testPasswordStatic() {
+ AddClusterOptions options = password("sekrit");
+ assertEquals(ImmutableList.of("sekrit"), options.buildQueryParameters().get("password"));
+ }
+
+ public void testPodId() {
+ AddClusterOptions options = new AddClusterOptions().podId(42L);
+ assertEquals(ImmutableList.of("42"), options.buildQueryParameters().get("podid"));
+ }
+
+ public void testPodIdStatic() {
+ AddClusterOptions options = podId(42L);
+ assertEquals(ImmutableList.of("42"), options.buildQueryParameters().get("podid"));
+ }
+
+ public void testUrl() {
+ AddClusterOptions options = new AddClusterOptions().url("http://example.com");
+ assertEquals(ImmutableList.of("http://example.com"), options.buildQueryParameters().get("url"));
+ }
+
+ public void testUrlStatic() {
+ AddClusterOptions options = url("http://example.com");
+ assertEquals(ImmutableList.of("http://example.com"), options.buildQueryParameters().get("url"));
+ }
+
+ public void testUsername() {
+ AddClusterOptions options = new AddClusterOptions().username("fred");
+ assertEquals(ImmutableList.of("fred"), options.buildQueryParameters().get("username"));
+ }
+
+ public void testUsernameStatic() {
+ AddClusterOptions options = username("fred");
+ assertEquals(ImmutableList.of("fred"), options.buildQueryParameters().get("username"));
+ }
+
+}
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/AddHostOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/AddHostOptionsTest.java
new file mode 100644
index 0000000..7dfd22f
--- /dev/null
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/AddHostOptionsTest.java
@@ -0,0 +1,87 @@
+/**
+ * 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.options;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.cloudstack.domain.Host;
+import org.testng.annotations.Test;
+
+import static org.jclouds.cloudstack.options.AddHostOptions.Builder.*;
+import static org.testng.Assert.assertEquals;
+
+/**
+ * Tests behavior of {@code AddHostOptions}
+ *
+ * @author Richard Downer
+ */
+@Test(groups = "unit")
+public class AddHostOptionsTest {
+
+ public void testAllocationState() {
+ AddHostOptions options = new AddHostOptions().allocationState(Host.AllocationState.ENABLED);
+ assertEquals(ImmutableList.of("Enabled"), options.buildQueryParameters().get("allocationstate"));
+ }
+
+ public void testAllocationStateStatic() {
+ AddHostOptions options = allocationState(Host.AllocationState.ENABLED);
+ assertEquals(ImmutableList.of("Enabled"), options.buildQueryParameters().get("allocationstate"));
+ }
+
+ public void testClusterId() {
+ AddHostOptions options = new AddHostOptions().clusterId(42L);
+ assertEquals(ImmutableList.of("42"), options.buildQueryParameters().get("clusterid"));
+ }
+
+ public void testClusterIdStatic() {
+ AddHostOptions options = clusterId(42L);
+ assertEquals(ImmutableList.of("42"), options.buildQueryParameters().get("clusterid"));
+ }
+
+ public void testClusterName() {
+ AddHostOptions options = new AddHostOptions().clusterName("Cluster Name");
+ assertEquals(ImmutableList.of("Cluster Name"), options.buildQueryParameters().get("clustername"));
+ }
+
+ public void testClusterNameStatic() {
+ AddHostOptions options = clusterName("Cluster Name");
+ assertEquals(ImmutableList.of("Cluster Name"), options.buildQueryParameters().get("clustername"));
+ }
+
+ public void testHostTags() {
+ AddHostOptions options = new AddHostOptions().hostTags(ImmutableSet.<String>of("foo", "bar", "baz"));
+ assertEquals(ImmutableList.of("foo,bar,baz"), options.buildQueryParameters().get("hosttags"));
+ }
+
+ public void testHostTagsStatic() {
+ AddHostOptions options = hostTags(ImmutableSet.<String>of("foo", "bar", "baz"));
+ assertEquals(ImmutableList.of("foo,bar,baz"), options.buildQueryParameters().get("hosttags"));
+ }
+
+ public void testPodId() {
+ AddHostOptions options = new AddHostOptions().podId(42L);
+ assertEquals(ImmutableList.of("42"), options.buildQueryParameters().get("podid"));
+ }
+
+ public void testPodIdStatic() {
+ AddHostOptions options = podId(42L);
+ assertEquals(ImmutableList.of("42"), options.buildQueryParameters().get("podid"));
+ }
+
+}
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/AddSecondaryStorageOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/AddSecondaryStorageOptionsTest.java
new file mode 100644
index 0000000..3d9ca51
--- /dev/null
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/AddSecondaryStorageOptionsTest.java
@@ -0,0 +1,45 @@
+/**
+ * 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.options;
+
+import com.google.common.collect.ImmutableList;
+import org.testng.annotations.Test;
+
+import static org.jclouds.cloudstack.options.AddSecondaryStorageOptions.Builder.*;
+import static org.testng.Assert.assertEquals;
+
+/**
+ * Tests behavior of {@code AddSecondaryStorageOptions}
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "unit")
+public class AddSecondaryStorageOptionsTest {
+
+ public void testZoneId() {
+ AddSecondaryStorageOptions options = new AddSecondaryStorageOptions().zoneId(6);
+ assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("zoneid"));
+ }
+
+ public void testZoneIdStatic() {
+ AddSecondaryStorageOptions options = zoneId(6);
+ assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("zoneid"));
+ }
+
+}
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/DeleteHostOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/DeleteHostOptionsTest.java
new file mode 100644
index 0000000..0445a2e
--- /dev/null
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/DeleteHostOptionsTest.java
@@ -0,0 +1,57 @@
+/**
+ * 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.options;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.cloudstack.domain.Host;
+import org.testng.annotations.Test;
+
+import static org.jclouds.cloudstack.options.DeleteHostOptions.Builder.*;
+import static org.testng.Assert.assertEquals;
+
+/**
+ * Tests behavior of {@code DeleteHostOptions}
+ *
+ * @author Richard Downer
+ */
+@Test(groups = "unit")
+public class DeleteHostOptionsTest {
+
+ public void testForced() {
+ DeleteHostOptions options = new DeleteHostOptions().forced(true);
+ assertEquals(ImmutableList.of("true"), options.buildQueryParameters().get("forced"));
+ }
+
+ public void testForcedStatic() {
+ DeleteHostOptions options = forced(true);
+ assertEquals(ImmutableList.of("true"), options.buildQueryParameters().get("forced"));
+ }
+
+ public void testForceDestroyLocalStorage() {
+ DeleteHostOptions options = new DeleteHostOptions().forceDestroyLocalStorage(true);
+ assertEquals(ImmutableList.of("true"), options.buildQueryParameters().get("forcedestroylocalstorage"));
+ }
+
+ public void testForceDestroyLocalStorageStatic() {
+ DeleteHostOptions options = forceDestroyLocalStorage(true);
+ assertEquals(ImmutableList.of("true"), options.buildQueryParameters().get("forcedestroylocalstorage"));
+ }
+
+}
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/UpdateClusterOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/UpdateClusterOptionsTest.java
new file mode 100644
index 0000000..0cb7db3
--- /dev/null
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/UpdateClusterOptionsTest.java
@@ -0,0 +1,67 @@
+/**
+ * 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.options;
+
+import com.google.common.collect.ImmutableList;
+import org.jclouds.cloudstack.domain.Cluster;
+import org.jclouds.cloudstack.domain.Host;
+import org.testng.annotations.Test;
+
+import static org.jclouds.cloudstack.options.UpdateClusterOptions.Builder.allocationState;
+import static org.testng.Assert.assertEquals;
+
+/**
+ * Tests behavior of {@code UpdateClusterOptions}
+ *
+ * @author Richard Downer
+ */
+@Test(groups = "unit")
+public class UpdateClusterOptionsTest {
+
+ public void testAllocationState() {
+ UpdateClusterOptions options = new UpdateClusterOptions().allocationState(Host.AllocationState.ENABLED);
+ assertEquals(ImmutableList.of("Enabled"), options.buildQueryParameters().get("allocationstate"));
+ }
+
+ public void testAllocationStateStatic() {
+ UpdateClusterOptions options = allocationState(Host.AllocationState.ENABLED);
+ assertEquals(ImmutableList.of("Enabled"), options.buildQueryParameters().get("allocationstate"));
+ }
+
+ public void testClusterName() {
+ UpdateClusterOptions options = new UpdateClusterOptions().clusterName("My Cluster");
+ assertEquals(ImmutableList.of("My Cluster"), options.buildQueryParameters().get("clustername"));
+ }
+
+ public void testClusterType() {
+ UpdateClusterOptions options = new UpdateClusterOptions().clusterType(Host.ClusterType.CLOUD_MANAGED);
+ assertEquals(ImmutableList.of("CloudManaged"), options.buildQueryParameters().get("clustertype"));
+ }
+
+ public void testHypervisor() {
+ UpdateClusterOptions options = new UpdateClusterOptions().hypervisor("XenServer");
+ assertEquals(ImmutableList.of("XenServer"), options.buildQueryParameters().get("hypervisor"));
+ }
+
+ public void testManagedState() {
+ UpdateClusterOptions options = new UpdateClusterOptions().managedState(Cluster.ManagedState.PREPARE_UNMANAGED);
+ assertEquals(ImmutableList.of("PrepareUnmanaged"), options.buildQueryParameters().get("managedstate"));
+ }
+
+}
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/UpdateHostOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/UpdateHostOptionsTest.java
new file mode 100644
index 0000000..69ffc18
--- /dev/null
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/UpdateHostOptionsTest.java
@@ -0,0 +1,67 @@
+/**
+ * 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.options;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.cloudstack.domain.Host;
+import org.testng.annotations.Test;
+
+import static org.jclouds.cloudstack.options.UpdateHostOptions.Builder.*;
+import static org.testng.Assert.assertEquals;
+
+/**
+ * Tests behavior of {@code UpdateHostOptions}
+ *
+ * @author Richard Downer
+ */
+@Test(groups = "unit")
+public class UpdateHostOptionsTest {
+
+ public void testAllocationState() {
+ UpdateHostOptions options = new UpdateHostOptions().allocationState(Host.AllocationState.ENABLED);
+ assertEquals(ImmutableList.of("Enabled"), options.buildQueryParameters().get("allocationstate"));
+ }
+
+ public void testAllocationStateStatic() {
+ UpdateHostOptions options = allocationState(Host.AllocationState.ENABLED);
+ assertEquals(ImmutableList.of("Enabled"), options.buildQueryParameters().get("allocationstate"));
+ }
+
+ public void testHostTags() {
+ UpdateHostOptions options = new UpdateHostOptions().hostTags(ImmutableSet.<String>of("foo", "bar", "baz"));
+ assertEquals(ImmutableList.of("foo,bar,baz"), options.buildQueryParameters().get("hosttags"));
+ }
+
+ public void testHostTagsStatic() {
+ UpdateHostOptions options = hostTags(ImmutableSet.<String>of("foo", "bar", "baz"));
+ assertEquals(ImmutableList.of("foo,bar,baz"), options.buildQueryParameters().get("hosttags"));
+ }
+
+ public void testOsCategoryId() {
+ UpdateHostOptions options = new UpdateHostOptions().osCategoryId(42L);
+ assertEquals(ImmutableList.of("42"), options.buildQueryParameters().get("oscategoryid"));
+ }
+
+ public void testOsCategoryIdStatic() {
+ UpdateHostOptions options = osCategoryId(42L);
+ assertEquals(ImmutableList.of("42"), options.buildQueryParameters().get("oscategoryid"));
+ }
+
+}
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListDomainsResponseTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListDomainsResponseTest.java
new file mode 100644
index 0000000..f6fa41a
--- /dev/null
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListDomainsResponseTest.java
@@ -0,0 +1,65 @@
+/**
+ * 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.parse;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import org.jclouds.cloudstack.config.CloudStackParserModule;
+import org.jclouds.cloudstack.domain.Domain;
+import org.jclouds.json.BaseSetParserTest;
+import org.jclouds.json.config.GsonModule;
+import org.jclouds.rest.annotations.SelectJson;
+import org.testng.annotations.Test;
+
+import java.util.Set;
+
+/**
+ * @author Andrei Savu
+ */
+@Test(groups = "unit")
+public class ListDomainsResponseTest extends BaseSetParserTest<Domain> {
+
+ @Override
+ protected Injector injector() {
+ return Guice.createInjector(new CloudStackParserModule(), new GsonModule() {
+ @Override
+ protected void configure() {
+ bind(DateAdapter.class).to(Iso8601DateAdapter.class);
+ super.configure();
+ }
+ });
+ }
+
+ @Override
+ public String resource() {
+ return "/listdomainsresponse.json";
+ }
+
+ @Override
+ @SelectJson("domain")
+ public Set<Domain> expected() {
+ return ImmutableSet.of(
+ Domain.builder().id(1L).name("ROOT").level(0).hasChild(true).build(),
+ Domain.builder().id(2L).name("jclouds1").level(1).parentDomainId(1)
+ .parentDomainName("ROOT").hasChild(false).build()
+ );
+ }
+
+}
diff --git a/apis/cloudstack/src/test/resources/addclusterresponse.json b/apis/cloudstack/src/test/resources/addclusterresponse.json
new file mode 100644
index 0000000..635a651
--- /dev/null
+++ b/apis/cloudstack/src/test/resources/addclusterresponse.json
@@ -0,0 +1 @@
+{ "addclusterresponse" : { "cluster" : {"warning":"this test data is fabricated","id":1,"name":"Xen Clust 1","podid":1,"podname":"Dev Pod 1","zoneid":1,"zonename":"Dev Zone 1","hypervisortype":"XenServer","clustertype":"CloudManaged","allocationstate":"Enabled","managedstate":"Managed"} } }
\ No newline at end of file
diff --git a/apis/cloudstack/src/test/resources/addhostresponse.json b/apis/cloudstack/src/test/resources/addhostresponse.json
new file mode 100644
index 0000000..7508410
--- /dev/null
+++ b/apis/cloudstack/src/test/resources/addhostresponse.json
@@ -0,0 +1,2 @@
+{ "addhostresponse" : { "host" :
+ {"warning":"This test data is fabricated","id":1,"name":"cs2-xevsrv.alucloud.local","state":"Up","type":"Routing","ipaddress":"10.26.26.107","zoneid":1,"zonename":"Dev Zone 1","podid":1,"podname":"Dev Pod 1","version":"2.2.12.20110928142833","hypervisor":"XenServer","cpunumber":24,"cpuspeed":2266,"cpuallocated":"2.76%","cpuused":"0.1%","cpuwithoverprovisioning":"54384.0","networkkbsread":4443,"networkkbswrite":15048,"memorytotal":100549733760,"memoryallocated":3623878656,"memoryused":3623878656,"capabilities":"xen-3.0-x86_64 , xen-3.0-x86_32p , hvm-3.0-x86_32 , hvm-3.0-x86_32p , hvm-3.0-x86_64","lastpinged":"1970-01-16T00:54:43+0200","managementserverid":223098941760041,"clusterid":1,"clustername":"Xen Clust 1","clustertype":"CloudManaged","islocalstorageactive":false,"created":"2011-11-26T23:28:36+0200","events":"PrepareUnmanaged; HypervisorVersionChanged; ManagementServerDown; PingTimeout; AgentDisconnected; MaintenanceRequested; HostDown; AgentConnected; StartAgentRebalance; ShutdownRequested; Ping","hosttags":"","hasEnoughCapacity":false,"allocationstate":"Enabled"} } }
\ No newline at end of file
diff --git a/apis/cloudstack/src/test/resources/addsecondarystorageresponse.json b/apis/cloudstack/src/test/resources/addsecondarystorageresponse.json
new file mode 100644
index 0000000..d164d9a
--- /dev/null
+++ b/apis/cloudstack/src/test/resources/addsecondarystorageresponse.json
@@ -0,0 +1,3 @@
+{ "addsecondarystorageresponse" : { "host" :
+ {"warning":"this test data is fabricated","id":2,"name":"nfs://10.26.26.165/mnt/nfs/cs_sec","state":"Alert","disconnected":"2011-11-26T23:33:38+0200","type":"SecondaryStorage","ipaddress":"nfs","zoneid":1,"zonename":"Dev Zone 1","version":"2.2.12.20110928142833","hypervisor":"None","lastpinged":"1970-01-16T00:42:30+0200","islocalstorageactive":false,"created":"2011-11-26T23:33:38+0200","events":"ManagementServerDown; AgentDisconnected; Remove; MaintenanceRequested; AgentConnected; Ping","hasEnoughCapacity":false,"allocationstate":"Enabled"},
+} }
\ No newline at end of file
diff --git a/apis/cloudstack/src/test/resources/cancelhostmaintenanceresponse.json b/apis/cloudstack/src/test/resources/cancelhostmaintenanceresponse.json
new file mode 100644
index 0000000..5c3b0d0
--- /dev/null
+++ b/apis/cloudstack/src/test/resources/cancelhostmaintenanceresponse.json
@@ -0,0 +1 @@
+{ "cancelhostmaintenanceresponse" : {"warning":"this test data is fabricated","jobid":2036,"id":2017} }
\ No newline at end of file
diff --git a/apis/cloudstack/src/test/resources/createdomainresponse.json b/apis/cloudstack/src/test/resources/createdomainresponse.json
new file mode 100644
index 0000000..c5882ab
--- /dev/null
+++ b/apis/cloudstack/src/test/resources/createdomainresponse.json
@@ -0,0 +1,2 @@
+{ "createdomainresponse" : { "domain" :
+ {"id":10,"name":"test","level":1,"parentdomainid":1,"parentdomainname":"ROOT","haschild":false} } }
\ No newline at end of file
diff --git a/apis/cloudstack/src/test/resources/deletedomainresponse.json b/apis/cloudstack/src/test/resources/deletedomainresponse.json
new file mode 100644
index 0000000..d617a15
--- /dev/null
+++ b/apis/cloudstack/src/test/resources/deletedomainresponse.json
@@ -0,0 +1 @@
+{ "deletedomainresponse" : {"jobid":2413} }
\ No newline at end of file
diff --git a/apis/cloudstack/src/test/resources/getdomainresponse.json b/apis/cloudstack/src/test/resources/getdomainresponse.json
new file mode 100644
index 0000000..a3baf57
--- /dev/null
+++ b/apis/cloudstack/src/test/resources/getdomainresponse.json
@@ -0,0 +1,2 @@
+{ "listdomainsresponse" : { "count":1 ,"domain" : [
+ {"id":1,"name":"ROOT","level":0,"haschild":true} ] } }
\ No newline at end of file
diff --git a/apis/cloudstack/src/test/resources/listdomainchildrenresponse.json b/apis/cloudstack/src/test/resources/listdomainchildrenresponse.json
new file mode 100644
index 0000000..5cd2289
--- /dev/null
+++ b/apis/cloudstack/src/test/resources/listdomainchildrenresponse.json
@@ -0,0 +1,3 @@
+{ "listdomainchildrenresponse" : { "count":2 ,"domain" : [
+ {"id":2,"name":"jclouds1","level":1,"parentdomainid":1,"parentdomainname":"ROOT","haschild":false},
+ {"id":3,"name":"jclouds2","level":1,"parentdomainid":1,"parentdomainname":"ROOT","haschild":false} ] } }
\ No newline at end of file
diff --git a/apis/cloudstack/src/test/resources/listdomainsresponse.json b/apis/cloudstack/src/test/resources/listdomainsresponse.json
new file mode 100644
index 0000000..79d7e00
--- /dev/null
+++ b/apis/cloudstack/src/test/resources/listdomainsresponse.json
@@ -0,0 +1,3 @@
+{ "listdomainsresponse" : { "count":2 ,"domain" : [
+ {"id":1,"name":"ROOT","level":0,"haschild":true},
+ {"id":2,"name":"jclouds1","level":1,"parentdomainid":1,"parentdomainname":"ROOT","haschild":false} ] } }
\ No newline at end of file
diff --git a/apis/cloudstack/src/test/resources/preparehostformaintenanceresponse.json b/apis/cloudstack/src/test/resources/preparehostformaintenanceresponse.json
new file mode 100644
index 0000000..294f646
--- /dev/null
+++ b/apis/cloudstack/src/test/resources/preparehostformaintenanceresponse.json
@@ -0,0 +1 @@
+{ "preparehostformaintenanceresponse" : {"warning":"this test data is fabricated","jobid":2036,"id":2017} }
\ No newline at end of file
diff --git a/apis/cloudstack/src/test/resources/reconnecthostresponse.json b/apis/cloudstack/src/test/resources/reconnecthostresponse.json
new file mode 100644
index 0000000..2b86f49
--- /dev/null
+++ b/apis/cloudstack/src/test/resources/reconnecthostresponse.json
@@ -0,0 +1 @@
+{ "reconnecthostresponse" : {"warning":"this test data is fabricated","jobid":2036,"id":2017} }
\ No newline at end of file
diff --git a/apis/cloudstack/src/test/resources/updateclusterresponse.json b/apis/cloudstack/src/test/resources/updateclusterresponse.json
new file mode 100644
index 0000000..4a03ca3
--- /dev/null
+++ b/apis/cloudstack/src/test/resources/updateclusterresponse.json
@@ -0,0 +1 @@
+{ "updateclusterresponse" : { "cluster" : {"warning":"this test data is fabricated","id":1,"name":"Xen Clust 1","podid":1,"podname":"Dev Pod 1","zoneid":1,"zonename":"Dev Zone 1","hypervisortype":"XenServer","clustertype":"CloudManaged","allocationstate":"Enabled","managedstate":"Managed"} } }
\ No newline at end of file
diff --git a/apis/cloudstack/src/test/resources/updatedomainresponse.json b/apis/cloudstack/src/test/resources/updatedomainresponse.json
new file mode 100644
index 0000000..1745eac
--- /dev/null
+++ b/apis/cloudstack/src/test/resources/updatedomainresponse.json
@@ -0,0 +1,2 @@
+{ "updatedomainresponse" : { "domain" :
+ {"id":10,"name":"test-2","level":1,"parentdomainid":1,"parentdomainname":"ROOT","haschild":false} } }
\ No newline at end of file
diff --git a/apis/cloudstack/src/test/resources/updatehostresponse.json b/apis/cloudstack/src/test/resources/updatehostresponse.json
new file mode 100644
index 0000000..cb70ddd
--- /dev/null
+++ b/apis/cloudstack/src/test/resources/updatehostresponse.json
@@ -0,0 +1,2 @@
+{ "updatehostresponse" : { "host" :
+ {"warning":"This test data is fabricated","id":1,"name":"cs2-xevsrv.alucloud.local","state":"Up","type":"Routing","ipaddress":"10.26.26.107","zoneid":1,"zonename":"Dev Zone 1","podid":1,"podname":"Dev Pod 1","version":"2.2.12.20110928142833","hypervisor":"XenServer","cpunumber":24,"cpuspeed":2266,"cpuallocated":"2.76%","cpuused":"0.1%","cpuwithoverprovisioning":"54384.0","networkkbsread":4443,"networkkbswrite":15048,"memorytotal":100549733760,"memoryallocated":3623878656,"memoryused":3623878656,"capabilities":"xen-3.0-x86_64 , xen-3.0-x86_32p , hvm-3.0-x86_32 , hvm-3.0-x86_32p , hvm-3.0-x86_64","lastpinged":"1970-01-16T00:54:43+0200","managementserverid":223098941760041,"clusterid":1,"clustername":"Xen Clust 1","clustertype":"CloudManaged","islocalstorageactive":false,"created":"2011-11-26T23:28:36+0200","events":"PrepareUnmanaged; HypervisorVersionChanged; ManagementServerDown; PingTimeout; AgentDisconnected; MaintenanceRequested; HostDown; AgentConnected; StartAgentRebalance; ShutdownRequested; Ping","hosttags":"","hasEnoughCapacity":false,"allocationstate":"Enabled"} } }
\ No newline at end of file
diff --git a/apis/ec2/src/test/java/org/jclouds/ec2/compute/internal/EC2TemplateBuilderImplTest.java b/apis/ec2/src/test/java/org/jclouds/ec2/compute/internal/EC2TemplateBuilderImplTest.java
index f17f70e..055028e 100644
--- a/apis/ec2/src/test/java/org/jclouds/ec2/compute/internal/EC2TemplateBuilderImplTest.java
+++ b/apis/ec2/src/test/java/org/jclouds/ec2/compute/internal/EC2TemplateBuilderImplTest.java
@@ -93,7 +93,14 @@
return new EC2TemplateBuilderImpl(locations, images, sizes, Suppliers.ofInstance(defaultLocation),
optionsProvider, templateBuilderProvider, Suppliers.<LoadingCache<RegionAndName, ? extends Image>>ofInstance(imageMap));
}
+
+ @Override
+ @Test
+ public void testHardwareWithImageIdPredicateOnlyAcceptsImageWhenLocationNull() {
+ // not possible to have null region in ec2
+ }
+
@SuppressWarnings("unchecked")
@Test
public void testParseOnDemand() {
diff --git a/apis/nova/pom.xml b/apis/nova/pom.xml
index 7444cf0..490f6dc 100644
--- a/apis/nova/pom.xml
+++ b/apis/nova/pom.xml
@@ -1,159 +1,153 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- 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.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.jclouds</groupId>
- <artifactId>jclouds-project</artifactId>
- <version>1.3.0-SNAPSHOT</version>
- <relativePath>../../project/pom.xml</relativePath>
- </parent>
- <groupId>org.jclouds.api</groupId>
- <artifactId>nova</artifactId>
- <name>jcloud nova api</name>
- <description>jclouds components to access an implementation of OpenStack Nova</description>
- <packaging>bundle</packaging>
-
- <properties>
- <test.nova.endpoint>http://localhost:8773/services/Cloud</test.nova.endpoint>
- <test.nova.api-version>1.1</test.nova.api-version>
- <test.nova.build-version />
- <test.nova.identity>FIXME_IDENTITY</test.nova.identity>
- <test.nova.credential>FIXME_CREDENTIALS</test.nova.credential>
- <test.nova.image-id />
- <test.nova.image.login-user />
- <test.nova.image.authenticate-sudo />
- <test.ssh.keyfile.public />
- <test.ssh.keyfile.private />
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>org.jclouds.common</groupId>
- <artifactId>openstack-common</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.jclouds</groupId>
- <artifactId>jclouds-compute</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.jclouds</groupId>
- <artifactId>jclouds-core</artifactId>
- <version>${project.version}</version>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.jclouds.common</groupId>
- <artifactId>openstack-common</artifactId>
- <version>${project.version}</version>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.jclouds</groupId>
- <artifactId>jclouds-compute</artifactId>
- <version>${project.version}</version>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.jclouds.driver</groupId>
- <artifactId>jclouds-sshj</artifactId>
- <version>${project.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.jclouds.driver</groupId>
- <artifactId>jclouds-log4j</artifactId>
- <version>${project.version}</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
- <profiles>
- <profile>
- <id>live</id>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <dependencies>
- <dependency>
- <groupId>org.apache.maven.surefire</groupId>
- <artifactId>surefire-testng</artifactId>
- </dependency>
- </dependencies>
- <executions>
- <execution>
- <id>integration</id>
- <phase>integration-test</phase>
- <goals>
- <goal>test</goal>
- </goals>
- <configuration>
- <systemPropertyVariables>
- <test.nova.endpoint>${test.nova.endpoint}</test.nova.endpoint>
- <test.nova.api-version>${test.nova.api-version}</test.nova.api-version>
- <test.nova.build-version>${test.nova.build-version}</test.nova.build-version>
- <test.nova.identity>${test.nova.identity}</test.nova.identity>
- <test.nova.credential>${test.nova.credential}</test.nova.credential>
- <test.nova.image-id>${test.nova.image-id}</test.nova.image-id>
- <test.nova.image.login-user>${test.nova.image.login-user}</test.nova.image.login-user>
- <test.nova.image.authenticate-sudo>${test.nova.image.authenticate-sudo}</test.nova.image.authenticate-sudo>
- <test.ssh.keyfile.public>${test.ssh.keyfile.public}</test.ssh.keyfile.public>
- <test.ssh.keyfile.private>${test.ssh.keyfile.private}</test.ssh.keyfile.private>
- </systemPropertyVariables>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
- </profile>
- </profiles>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <configuration>
- <instructions>
- <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
- <Export-Package>org.jclouds.openstack.nova.*;version="${project.version}"</Export-Package>
- <Import-Package>
- org.jclouds.compute.internal;version="${project.version}",
- org.jclouds.rest.internal;version="${project.version}",
- org.jclouds.*;version="${project.version}",
- *
- </Import-Package>
- </instructions>
- </configuration>
- </plugin>
- </plugins>
- </build>
-
-</project>
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.jclouds</groupId>
+ <artifactId>jclouds-project</artifactId>
+ <version>1.3.0-SNAPSHOT</version>
+ <relativePath>../../project/pom.xml</relativePath>
+ </parent>
+ <groupId>org.jclouds.api</groupId>
+ <artifactId>nova</artifactId>
+ <name>jcloud nova api</name>
+ <description>jclouds components to access an implementation of OpenStack Nova</description>
+ <packaging>bundle</packaging>
+
+ <properties>
+ <test.nova.endpoint>http://localhost:8773/services/Cloud</test.nova.endpoint>
+ <test.nova.api-version>1.1</test.nova.api-version>
+ <test.nova.build-version></test.nova.build-version>
+ <test.nova.identity>FIXME_IDENTITY</test.nova.identity>
+ <test.nova.credential>FIXME_CREDENTIALS</test.nova.credential>
+ <test.nova.image-id></test.nova.image-id>
+ <test.nova.image.login-user></test.nova.image.login-user>
+ <test.nova.image.authenticate-sudo></test.nova.image.authenticate-sudo>
+ <test.ssh.keyfile.public></test.ssh.keyfile.public>
+ <test.ssh.keyfile.private></test.ssh.keyfile.private>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.jclouds.common</groupId>
+ <artifactId>openstack-common</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jclouds</groupId>
+ <artifactId>jclouds-compute</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jclouds</groupId>
+ <artifactId>jclouds-core</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jclouds.common</groupId>
+ <artifactId>openstack-common</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jclouds</groupId>
+ <artifactId>jclouds-compute</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jclouds.driver</groupId>
+ <artifactId>jclouds-sshj</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jclouds.driver</groupId>
+ <artifactId>jclouds-log4j</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <profiles>
+ <profile>
+ <id>live</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>integration</id>
+ <phase>integration-test</phase>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <systemPropertyVariables>
+ <test.nova.endpoint>${test.nova.endpoint}</test.nova.endpoint>
+ <test.nova.api-version>${test.nova.api-version}</test.nova.api-version>
+ <test.nova.build-version>${test.nova.build-version}</test.nova.build-version>
+ <test.nova.identity>${test.nova.identity}</test.nova.identity>
+ <test.nova.credential>${test.nova.credential}</test.nova.credential>
+ <test.nova.image-id>${test.nova.image-id}</test.nova.image-id>
+ <test.nova.image.login-user>${test.nova.image.login-user}</test.nova.image.login-user>
+ <test.nova.image.authenticate-sudo>${test.nova.image.authenticate-sudo}</test.nova.image.authenticate-sudo>
+ <test.ssh.keyfile.public>${test.ssh.keyfile.public}</test.ssh.keyfile.public>
+ <test.ssh.keyfile.private>${test.ssh.keyfile.private}</test.ssh.keyfile.private>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Export-Package>org.jclouds.openstack.nova.*;version="${project.version}"</Export-Package>
+ <Import-Package>
+ org.jclouds.compute.internal;version="${project.version}",
+ org.jclouds.rest.internal;version="${project.version}",
+ org.jclouds.*;version="${project.version}",
+ *
+ </Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaAsyncClient.java b/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaAsyncClient.java
index 0423aa2..505f76d 100644
--- a/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaAsyncClient.java
+++ b/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaAsyncClient.java
@@ -317,5 +317,28 @@
@Path("/servers/{id}/ips/private")
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<? extends Set<String>> listPrivateAddresses(@PathParam("id") int serverId);
+
+ @POST
+ @Path("/servers/{id}/action")
+ @Consumes
+ @Produces(MediaType.APPLICATION_JSON)
+ @Payload("%7B\"addFloatingIp\":%7B\"address\":\"{address}\"%7D%7D")
+ ListenableFuture<Void> addFloatingIP(@PathParam("id") int serverId, @PayloadParam("address") String ip);
+
+ @GET
+ @Unwrap
+ @Consumes(MediaType.APPLICATION_JSON)
+ @QueryParams(keys = "format", values = "json")
+ @Path("/os-floating-ips")
+ @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
+ ListenableFuture<? extends Set<FloatingIP>> listFloatingIPs();
+
+ @GET
+ @Unwrap
+ @Consumes(MediaType.APPLICATION_JSON)
+ @QueryParams(keys = "format", values = "json")
+ @Path("/os-floating-ips/{id}")
+ @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+ ListenableFuture<FloatingIP> getFloatingIP(@PathParam("id") int id);
}
diff --git a/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaClient.java b/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaClient.java
index 56ab0d8..45a32e7 100644
--- a/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaClient.java
+++ b/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaClient.java
@@ -26,6 +26,7 @@
import org.jclouds.concurrent.Timeout;
import org.jclouds.openstack.nova.domain.Addresses;
import org.jclouds.openstack.nova.domain.Flavor;
+import org.jclouds.openstack.nova.domain.FloatingIP;
import org.jclouds.openstack.nova.domain.Image;
import org.jclouds.openstack.nova.domain.RebootType;
import org.jclouds.openstack.nova.domain.Server;
@@ -281,4 +282,35 @@
*/
Set<String> listPrivateAddresses(int serverId);
+ /**
+ * Add a floating IP to the given server. The floating IP can just be added
+ * if the server has a fixed IP. It means that it is not possible to
+ * directly add the floating IP just after creating the server but have to
+ * poll if the server has an IP.
+ *
+ * @see <a href="http://wiki.openstack.org/os_api_floating_ip">http://wiki.openstack.org/os_api_floating_ip</a>
+ * @since 2011.3 "Diablo" release, OpenStack API 1.1
+ * @param serverId
+ * @param ip
+ */
+ void addFloatingIP(int serverId, String ip);
+
+ /**
+ * Get all the defined floating IPs in nova
+ *
+ * @see <a href="http://wiki.openstack.org/os_api_floating_ip">http://wiki.openstack.org/os_api_floating_ip</a>
+ * @since 2011.3 "Diablo" release, OpenStack API 1.1
+ * @return all the available floating IP for the current tenant
+ */
+ Set<FloatingIP> listFloatingIPs();
+
+ /**
+ * Get floating IP details from its ID
+ *
+ * @see <a href="http://wiki.openstack.org/os_api_floating_ip">http://wiki.openstack.org/os_api_floating_ip</a>
+ * @since 2011.3 "Diablo" release, OpenStack API 1.1
+ * @param id the floating IP id
+ * @return the floating IP or null if not found
+ */
+ FloatingIP getFloatingIP(int id);
}
diff --git a/apis/nova/src/main/java/org/jclouds/openstack/nova/domain/FloatingIP.java b/apis/nova/src/main/java/org/jclouds/openstack/nova/domain/FloatingIP.java
new file mode 100644
index 0000000..cefc53b
--- /dev/null
+++ b/apis/nova/src/main/java/org/jclouds/openstack/nova/domain/FloatingIP.java
@@ -0,0 +1,170 @@
+/**
+ * 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.openstack.nova.domain;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Check <a href="http://wiki.openstack.org/os_api_floating_ip">Floating IP Wiki
+ * page</a>. Available since OpenStack Diablo release and API 1.1.
+ *
+ * @author chamerling
+ *
+ */
+public class FloatingIP extends Resource {
+
+ private int id;
+
+ private String ip;
+
+ @SerializedName(value="fixed_ip")
+ private String fixedIP;
+
+ @SerializedName(value = "instance_id")
+ private int instanceID;
+
+ @SuppressWarnings("unused")
+ private FloatingIP() {
+ }
+
+ public FloatingIP(int id, String ip, String fixedIP, int instanceID) {
+ this.id = id;
+ this.ip = ip;
+ this.fixedIP = fixedIP;
+ this.instanceID = instanceID;
+ }
+
+ /**
+ * @return the id
+ */
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * @param id the id to set
+ */
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ /**
+ * @return the ip
+ */
+ public String getIp() {
+ return ip;
+ }
+
+ /**
+ * @param ip the ip to set
+ */
+ public void setIp(String ip) {
+ this.ip = ip;
+ }
+
+ /**
+ * @return the fixedIP
+ */
+ public String getFixedIP() {
+ return fixedIP;
+ }
+
+ /**
+ * @param fixedIP the fixedIP to set
+ */
+ public void setFixedIP(String fixedIP) {
+ this.fixedIP = fixedIP;
+ }
+
+ /**
+ * @return the instanceID
+ */
+ public int getInstanceID() {
+ return instanceID;
+ }
+
+ /**
+ * @param instanceID the instanceID to set
+ */
+ public void setInstanceID(int instanceID) {
+ this.instanceID = instanceID;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("FloatingIP [id=");
+ builder.append(id);
+ builder.append(", ip=");
+ builder.append(ip);
+ builder.append(", fixedIP=");
+ builder.append(fixedIP);
+ builder.append(", instanceID=");
+ builder.append(instanceID);
+ builder.append("]");
+ return builder.toString();
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((fixedIP == null) ? 0 : fixedIP.hashCode());
+ result = prime * result + id;
+ result = prime * result + instanceID;
+ result = prime * result + ((ip == null) ? 0 : ip.hashCode());
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ FloatingIP other = (FloatingIP) obj;
+ if (fixedIP == null) {
+ if (other.fixedIP != null)
+ return false;
+ } else if (!fixedIP.equals(other.fixedIP))
+ return false;
+ if (id != other.id)
+ return false;
+ if (instanceID != other.instanceID)
+ return false;
+ if (ip == null) {
+ if (other.ip != null)
+ return false;
+ } else if (!ip.equals(other.ip))
+ return false;
+ return true;
+ }
+
+}
diff --git a/apis/nova/src/main/java/org/jclouds/openstack/nova/domain/Server.java b/apis/nova/src/main/java/org/jclouds/openstack/nova/domain/Server.java
index a375165..cc34084 100644
--- a/apis/nova/src/main/java/org/jclouds/openstack/nova/domain/Server.java
+++ b/apis/nova/src/main/java/org/jclouds/openstack/nova/domain/Server.java
@@ -19,6 +19,7 @@
package org.jclouds.openstack.nova.domain;
import com.google.common.collect.Maps;
+import com.google.gson.annotations.SerializedName;
import java.util.Date;
import java.util.Map;
@@ -45,6 +46,9 @@
private Flavor flavor;
private Image image;
+ @SerializedName(value="key_name")
+ private String keyName;
+
private Date created;
private Date updated;
@@ -191,6 +195,14 @@
public void setImage(Image image) {
this.image = image;
}
+
+ public String getKeyName() {
+ return keyName;
+ }
+
+ public void setKeyName(String keyName) {
+ this.keyName = keyName;
+ }
@Override
public int hashCode() {
@@ -204,6 +216,7 @@
result = prime * result + ((imageRef == null) ? 0 : imageRef.hashCode());
result = prime * result + ((metadata == null) ? 0 : metadata.hashCode());
result = prime * result + ((uuid == null) ? 0 : uuid.hashCode());
+ result = prime * result + ((keyName == null) ? 0 : keyName.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((flavor == null) ? 0 : flavor.hashCode());
result = prime * result + ((image == null) ? 0 : image.hashCode());
@@ -256,6 +269,11 @@
return false;
} else if (!uuid.equals(other.uuid))
return false;
+ if (keyName == null) {
+ if (other.keyName != null)
+ return false;
+ } else if (!keyName.equals(other.keyName))
+ return false;
if (name == null) {
if (other.name != null)
return false;
@@ -282,7 +300,7 @@
public String toString() {
return "Server [addresses=" + addresses + ", adminPass=" + adminPass + ", flavorRef="
+ flavorRef + ", hostId=" + hostId + ", id=" + id + ", imageRef=" + imageRef
- + ", metadata=" + metadata + ", uuid=" + uuid + ", name=" + name + "]";
+ + ", metadata=" + metadata + ", uuid=" + uuid + ", name=" + name + ", keyName=" + keyName + "]";
}
}
diff --git a/apis/nova/src/main/java/org/jclouds/openstack/nova/options/CreateServerOptions.java b/apis/nova/src/main/java/org/jclouds/openstack/nova/options/CreateServerOptions.java
index 97f69a9..185ee33 100644
--- a/apis/nova/src/main/java/org/jclouds/openstack/nova/options/CreateServerOptions.java
+++ b/apis/nova/src/main/java/org/jclouds/openstack/nova/options/CreateServerOptions.java
@@ -76,6 +76,7 @@
final String flavorRef;
Map<String, String> metadata;
List<File> personality;
+ String key_name;
private ServerRequest(String name, String imageRef, String flavorRef) {
this.name = name;
@@ -87,6 +88,7 @@
private Map<String, String> metadata = Maps.newHashMap();
private List<File> files = Lists.newArrayList();
+ private String keyName;
@Override
public <R extends HttpRequest> R bindToRequest(R request, Map<String, String> postParams) {
@@ -97,6 +99,8 @@
server.metadata = metadata;
if (files.size() > 0)
server.personality = files;
+ if (keyName != null)
+ server.key_name = keyName;
return bindToRequest(request, ImmutableMap.of("server", server));
}
@@ -144,6 +148,19 @@
return this;
}
+ /**
+ * A keypair name can be defined when creating a server. This key will be
+ * linked to the server and used to SSH connect to the machine
+ *
+ * @param keyName
+ * @return
+ */
+ public CreateServerOptions withKeyName(String keyName) {
+ checkNotNull(keyName, "keyName");
+ this.keyName = keyName;
+ return this;
+ }
+
public static class Builder {
/**
@@ -161,6 +178,14 @@
CreateServerOptions options = new CreateServerOptions();
return options.withMetadata(metadata);
}
+
+ /**
+ * @see CreateServerOptions#withKeyName(String)
+ */
+ public static CreateServerOptions withKeyName(String keyName) {
+ CreateServerOptions options = new CreateServerOptions();
+ return options.withKeyName(keyName);
+ }
}
@Override
diff --git a/apis/nova/src/test/java/org/jclouds/openstack/nova/NovaAsyncClientTest.java b/apis/nova/src/test/java/org/jclouds/openstack/nova/NovaAsyncClientTest.java
index 47d8444..79e4898 100644
--- a/apis/nova/src/test/java/org/jclouds/openstack/nova/NovaAsyncClientTest.java
+++ b/apis/nova/src/test/java/org/jclouds/openstack/nova/NovaAsyncClientTest.java
@@ -58,6 +58,7 @@
import static org.jclouds.openstack.nova.options.ListOptions.Builder.changesSince;
import static org.jclouds.openstack.nova.options.ListOptions.Builder.withDetails;
import static org.jclouds.openstack.nova.options.RebuildServerOptions.Builder.withImage;
+//import static org.junit.Assert.*;
import static org.testng.Assert.assertEquals;
/**
@@ -132,6 +133,26 @@
checkFilters(request);
+ }
+
+ @Test
+ public void testCreateServerWithKeyName() throws Exception {
+ Method method = NovaAsyncClient.class.getMethod("createServer", String.class, String.class, String.class,
+ createServerOptionsVarargsClass);
+ HttpRequest request = processor.createRequest(method, "ralphie", 2, 1,
+ withMetadata(ImmutableMap.of("foo", "bar")).withKeyName("mykey"));
+
+ assertRequestLineEquals(request, "POST http://endpoint/vapi-version/servers?format=json HTTP/1.1");
+ assertNonPayloadHeadersEqual(request, "Accept: application/json\n");
+ assertPayloadEquals(request,
+ "{\"server\":{\"name\":\"ralphie\",\"imageRef\":\"2\",\"flavorRef\":\"1\",\"metadata\":{\"foo\":\"bar\"},\"key_name\":\"mykey\"}}",
+ "application/json", false);
+
+ assertResponseParserClassEquals(method, request, UnwrapOnlyJsonValue.class);
+ assertSaxResponseParserClassEquals(method, null);
+ assertExceptionParserClassEquals(method, null);
+
+ checkFilters(request);
}
public void testDeleteImage() throws IOException, SecurityException, NoSuchMethodException {
@@ -635,8 +656,44 @@
assertExceptionParserClassEquals(method, null);
checkFilters(request);
- }
-
+ }
+
+ public void testGetFloatingIP() throws SecurityException,
+ NoSuchMethodException {
+ Method method = NovaAsyncClient.class.getMethod("getFloatingIP",
+ int.class);
+ HttpRequest request = processor.createRequest(method, 2);
+
+ assertRequestLineEquals(request,
+ "GET http://endpoint/vapi-version/os-floating-ips/2?format=json HTTP/1.1");
+ assertNonPayloadHeadersEqual(request, "Accept: application/json\n");
+ assertPayloadEquals(request, null, null, false);
+
+ assertResponseParserClassEquals(method, request,
+ UnwrapOnlyJsonValue.class);
+ assertSaxResponseParserClassEquals(method, null);
+ assertExceptionParserClassEquals(method,
+ ReturnNullOnNotFoundOr404.class);
+
+ checkFilters(request);
+ }
+
+ public void testListFloatingIPs() throws SecurityException, NoSuchMethodException {
+ Method method = NovaAsyncClient.class.getMethod("listFloatingIPs");
+ HttpRequest request = processor.createRequest(method);
+
+ assertRequestLineEquals(request,
+ "GET http://endpoint/vapi-version/os-floating-ips?format=json HTTP/1.1");
+ assertNonPayloadHeadersEqual(request, "Accept: application/json\n");
+ assertPayloadEquals(request, null, null, false);
+
+ assertResponseParserClassEquals(method, request, UnwrapOnlyJsonValue.class);
+ assertSaxResponseParserClassEquals(method, null);
+ assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
+
+ checkFilters(request);
+ }
+
@Override
protected TypeLiteral<RestAnnotationProcessor<NovaAsyncClient>> createTypeLiteral() {
return new TypeLiteral<RestAnnotationProcessor<NovaAsyncClient>>() {
diff --git a/apis/nova/src/test/java/org/jclouds/openstack/nova/functions/ParseFloatingIPFromJsonResponse.java b/apis/nova/src/test/java/org/jclouds/openstack/nova/functions/ParseFloatingIPFromJsonResponse.java
new file mode 100644
index 0000000..9d66665
--- /dev/null
+++ b/apis/nova/src/test/java/org/jclouds/openstack/nova/functions/ParseFloatingIPFromJsonResponse.java
@@ -0,0 +1,72 @@
+/**
+ * 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.openstack.nova.functions;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.UnwrapOnlyJsonValue;
+import org.jclouds.io.Payloads;
+import org.jclouds.json.config.GsonModule;
+import org.jclouds.openstack.nova.domain.FloatingIP;
+import org.testng.annotations.Test;
+
+import com.google.gson.Gson;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.TypeLiteral;
+
+/**
+ * @author chamerling
+ *
+ */
+@Test(groups = "unit")
+public class ParseFloatingIPFromJsonResponse {
+
+ @Test
+ public void testParseFloatingIPFromJsonResponseTest() throws IOException {
+ FloatingIP response = parseFLoatingIP();
+
+ String json = new Gson().toJson(response);
+ assertNotNull(json);
+
+ assertEquals(response.getId(), 1);
+ assertEquals(response.getFixedIP(), "10.0.0.2");
+ assertEquals(response.getInstanceID(), 123);
+ assertEquals(response.getIp(), "10.0.0.3");
+ }
+
+ public static FloatingIP parseFLoatingIP() {
+ Injector i = Guice.createInjector(new GsonModule());
+
+ InputStream is = ParseFloatingIPFromJsonResponse.class
+ .getResourceAsStream("/test_get_floatingip.json");
+
+ UnwrapOnlyJsonValue<FloatingIP> parser = i.getInstance(Key
+ .get(new TypeLiteral<UnwrapOnlyJsonValue<FloatingIP>>() {
+ }));
+ return parser.apply(new HttpResponse(200, "ok", Payloads
+ .newInputStreamPayload(is)));
+ }
+}
diff --git a/apis/nova/src/test/java/org/jclouds/openstack/nova/functions/ParseFloatingIPListFromJsonResponse.java b/apis/nova/src/test/java/org/jclouds/openstack/nova/functions/ParseFloatingIPListFromJsonResponse.java
new file mode 100644
index 0000000..a198a35
--- /dev/null
+++ b/apis/nova/src/test/java/org/jclouds/openstack/nova/functions/ParseFloatingIPListFromJsonResponse.java
@@ -0,0 +1,62 @@
+/**
+ * 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.openstack.nova.functions;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.InputStream;
+import java.net.UnknownHostException;
+import java.util.List;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.UnwrapOnlyJsonValue;
+import org.jclouds.io.Payloads;
+import org.jclouds.json.config.GsonModule;
+import org.jclouds.openstack.nova.domain.FloatingIP;
+import org.testng.annotations.Test;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.TypeLiteral;
+
+/**
+ * @author chamerling
+ *
+ */
+@Test(groups = "unit")
+public class ParseFloatingIPListFromJsonResponse {
+ Injector i = Guice.createInjector(new GsonModule());
+
+ @Test
+ public void testParseFloatingIPListFromJsonResponseTest() throws UnknownHostException {
+ InputStream is = getClass().getResourceAsStream(
+ "/test_list_floatingips.json");
+
+ UnwrapOnlyJsonValue<List<FloatingIP>> parser = i.getInstance(Key
+ .get(new TypeLiteral<UnwrapOnlyJsonValue<List<FloatingIP>>>() {
+ }));
+ List<FloatingIP> response = parser.apply(new HttpResponse(200, "ok",
+ Payloads.newInputStreamPayload(is)));
+
+ assertEquals(response.size(), 1);
+ FloatingIP floatingIP = new FloatingIP(1, "10.0.0.3", "11.0.0.1", 12);
+ assertEquals(response.get(0), floatingIP);
+ }
+}
diff --git a/apis/nova/src/test/resources/test_get_floatingip.json b/apis/nova/src/test/resources/test_get_floatingip.json
new file mode 100644
index 0000000..c2411fd
--- /dev/null
+++ b/apis/nova/src/test/resources/test_get_floatingip.json
@@ -0,0 +1,9 @@
+{
+ "floating_ip" :
+ {
+ "id" : 1,
+ "ip" : "10.0.0.3",
+ "fixed_ip" : "10.0.0.2",
+ "instance_id" : 123
+ }
+}
\ No newline at end of file
diff --git a/apis/nova/src/test/resources/test_list_floatingips.json b/apis/nova/src/test/resources/test_list_floatingips.json
new file mode 100644
index 0000000..f4910cb
--- /dev/null
+++ b/apis/nova/src/test/resources/test_list_floatingips.json
@@ -0,0 +1,10 @@
+{
+ "floating_ips" : [
+ {
+ "id" : 1,
+ "ip" : "10.0.0.3",
+ "fixed_ip": "11.0.0.1",
+ "instance_id": 12
+ }
+ ]
+}
\ No newline at end of file
diff --git a/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3AsyncBlobStore.java b/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3AsyncBlobStore.java
index 28121c3..7f2a5b6 100644
--- a/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3AsyncBlobStore.java
+++ b/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3AsyncBlobStore.java
@@ -232,6 +232,12 @@
*/
@Override
public ListenableFuture<String> putBlob(String container, Blob blob) {
+ return putBlob(container, blob, PutOptions.NONE);
+ }
+
+ @Override
+ public ListenableFuture<String> putBlob(String container, Blob blob, PutOptions overrides) {
+ // TODO: Make use of options overrides
PutObjectOptions options = new PutObjectOptions();
try {
AccessControlList acl = bucketAcls.getUnchecked(container);
@@ -257,12 +263,6 @@
}
@Override
- public ListenableFuture<String> putBlob(String container, Blob blob, PutOptions options) {
- // TODO implement options
- return putBlob(container, blob);
- }
-
- @Override
public ListenableFuture<Boolean> createContainerInLocation(Location location, String container,
CreateContainerOptions options) {
PutBucketOptions putBucketOptions = new PutBucketOptions();
diff --git a/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3BlobStore.java b/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3BlobStore.java
index b8e16a0..6f8d01a 100644
--- a/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3BlobStore.java
+++ b/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3BlobStore.java
@@ -232,15 +232,7 @@
*/
@Override
public String putBlob(String container, Blob blob) {
- PutObjectOptions options = new PutObjectOptions();
- try {
- AccessControlList acl = bucketAcls.getUnchecked(container);
- if (acl != null && acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ))
- options.withAcl(CannedAccessPolicy.PUBLIC_READ);
- } catch (CacheLoader.InvalidCacheLoadException e) {
- // nulls not permitted from cache loader
- }
- return sync.putObject(container, blob2Object.apply(blob), options);
+ return putBlob(container, blob, PutOptions.NONE);
}
/**
@@ -252,9 +244,17 @@
* object
*/
@Override
- public String putBlob(String container, Blob blob, PutOptions options) {
- // TODO implement options
- return putBlob(container, blob);
+ public String putBlob(String container, Blob blob, PutOptions overrides) {
+ // TODO: Make use of options overrides
+ PutObjectOptions options = new PutObjectOptions();
+ try {
+ AccessControlList acl = bucketAcls.getUnchecked(container);
+ if (acl != null && acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ))
+ options.withAcl(CannedAccessPolicy.PUBLIC_READ);
+ } catch (CacheLoader.InvalidCacheLoadException e) {
+ // nulls not permitted from cache loader
+ }
+ return sync.putObject(container, blob2Object.apply(blob), options);
}
/**
diff --git a/apis/s3/src/main/java/org/jclouds/s3/blobstore/functions/BlobToObjectMetadata.java b/apis/s3/src/main/java/org/jclouds/s3/blobstore/functions/BlobToObjectMetadata.java
index 9229e62..7bfdfee 100644
--- a/apis/s3/src/main/java/org/jclouds/s3/blobstore/functions/BlobToObjectMetadata.java
+++ b/apis/s3/src/main/java/org/jclouds/s3/blobstore/functions/BlobToObjectMetadata.java
@@ -28,9 +28,11 @@
import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.s3.domain.MutableObjectMetadata;
+import org.jclouds.s3.domain.ObjectMetadata;
import org.jclouds.s3.domain.internal.MutableObjectMetadataImpl;
import com.google.common.base.Function;
+import org.jclouds.s3.reference.S3Headers;
/**
* @author Adrian Cole
diff --git a/apis/s3/src/main/java/org/jclouds/s3/options/PutObjectOptions.java b/apis/s3/src/main/java/org/jclouds/s3/options/PutObjectOptions.java
index ffdb53e..ddc6d7b 100644
--- a/apis/s3/src/main/java/org/jclouds/s3/options/PutObjectOptions.java
+++ b/apis/s3/src/main/java/org/jclouds/s3/options/PutObjectOptions.java
@@ -34,6 +34,7 @@
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
+import org.jclouds.s3.domain.ObjectMetadata;
/**
* Contains options supported in the REST API for the PUT object operation.
diff --git a/apis/s3/src/test/java/org/jclouds/s3/S3ClientExpectTest.java b/apis/s3/src/test/java/org/jclouds/s3/S3ClientExpectTest.java
index 4fb0c87..ce23753 100644
--- a/apis/s3/src/test/java/org/jclouds/s3/S3ClientExpectTest.java
+++ b/apis/s3/src/test/java/org/jclouds/s3/S3ClientExpectTest.java
@@ -34,7 +34,8 @@
@Test(groups = "unit", testName = "S3ClientExpectTest")
public class S3ClientExpectTest extends BaseS3ClientExpectTest {
- public void bucketExistsReturnsTrueOn200AndFalseOn404() {
+ @Test
+ public void testBucketExistsReturnsTrueOn200AndFalseOn404() {
HttpRequest bucketFooExists = HttpRequest.builder().method("HEAD").endpoint(
URI.create("https://foo.s3.amazonaws.com/?max-keys=0")).headers(
diff --git a/sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/compute/VirtacoreVCloudExpressComputeServiceLiveTest.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/TaskInErrorStateException.java
similarity index 62%
copy from sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/compute/VirtacoreVCloudExpressComputeServiceLiveTest.java
copy to apis/vcloud/src/main/java/org/jclouds/vcloud/TaskInErrorStateException.java
index a172d5f..94908a3 100644
--- a/sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/compute/VirtacoreVCloudExpressComputeServiceLiveTest.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/TaskInErrorStateException.java
@@ -16,25 +16,28 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.jclouds.virtacore.vcloudexpress.compute;
+package org.jclouds.vcloud;
-import org.jclouds.vcloud.compute.VCloudComputeServiceLiveTest;
-import org.testng.annotations.Test;
+import org.jclouds.vcloud.domain.Task;
/**
*
- *
* @author Adrian Cole
+ *
*/
-@Test(groups = "live", enabled = true, singleThreaded = true)
-public class VirtacoreVCloudExpressComputeServiceLiveTest extends VCloudComputeServiceLiveTest {
- public VirtacoreVCloudExpressComputeServiceLiveTest() {
- provider = "virtacore-vcloudexpress";
+public class TaskInErrorStateException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ private final Task task;
+
+ public TaskInErrorStateException(Task task) {
+ super("error on task: " + task + " error: " + task.getError());
+ this.task = task;
}
- @Override
- public void setServiceDefaults() {
- group = "director";
+ public Task getTask() {
+ return task;
}
}
diff --git a/sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/compute/VirtacoreVCloudExpressComputeServiceLiveTest.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/TaskStillRunningException.java
similarity index 62%
copy from sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/compute/VirtacoreVCloudExpressComputeServiceLiveTest.java
copy to apis/vcloud/src/main/java/org/jclouds/vcloud/TaskStillRunningException.java
index a172d5f..c0b4774 100644
--- a/sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/compute/VirtacoreVCloudExpressComputeServiceLiveTest.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/TaskStillRunningException.java
@@ -16,25 +16,28 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.jclouds.virtacore.vcloudexpress.compute;
+package org.jclouds.vcloud;
-import org.jclouds.vcloud.compute.VCloudComputeServiceLiveTest;
-import org.testng.annotations.Test;
+import org.jclouds.vcloud.domain.Task;
/**
*
- *
* @author Adrian Cole
+ *
*/
-@Test(groups = "live", enabled = true, singleThreaded = true)
-public class VirtacoreVCloudExpressComputeServiceLiveTest extends VCloudComputeServiceLiveTest {
- public VirtacoreVCloudExpressComputeServiceLiveTest() {
- provider = "virtacore-vcloudexpress";
+public class TaskStillRunningException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ private final Task task;
+
+ public TaskStillRunningException(Task task) {
+ super("task still running: " + task);
+ this.task = task;
}
- @Override
- public void setServiceDefaults() {
- group = "director";
+ public Task getTask() {
+ return task;
}
}
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/VCloudPropertiesBuilder.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/VCloudPropertiesBuilder.java
index e28babc..c24533e 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/VCloudPropertiesBuilder.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/VCloudPropertiesBuilder.java
@@ -49,7 +49,8 @@
properties.setProperty(PROPERTY_VCLOUD_DEFAULT_FENCEMODE, FenceMode.BRIDGED.toString());
// TODO integrate this with the {@link ComputeTimeouts} instead of having a single timeout for
// everything.
- properties.setProperty(PROPERTY_VCLOUD_TIMEOUT_TASK_COMPLETED, 600l * 1000l + "");
+ properties.setProperty(PROPERTY_VCLOUD_TIMEOUT_TASK_COMPLETED, 1200l * 1000l + "");
+ properties.setProperty(PROPERTY_SESSION_INTERVAL, 300 + "");
return properties;
}
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayload.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayload.java
index 984d5bf..a6aebc2 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayload.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayload.java
@@ -21,7 +21,7 @@
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
-import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_FENCEMODE;
+import static com.google.common.collect.Iterables.transform;
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_NAMESPACE;
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_SCHEMA;
@@ -30,8 +30,7 @@
import java.util.Properties;
import java.util.Set;
-import org.jclouds.javax.annotation.Nullable;
-import javax.annotation.Resource;
+import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.xml.parsers.FactoryConfigurationError;
@@ -39,11 +38,10 @@
import javax.xml.transform.TransformerException;
import org.jclouds.http.HttpRequest;
-import org.jclouds.logging.Logger;
+import org.jclouds.javax.annotation.Nullable;
import org.jclouds.rest.MapBinder;
import org.jclouds.rest.binders.BindToStringPayload;
import org.jclouds.rest.internal.GeneratedHttpRequest;
-import org.jclouds.vcloud.VCloudClient;
import org.jclouds.vcloud.domain.ReferenceType;
import org.jclouds.vcloud.domain.VAppTemplate;
import org.jclouds.vcloud.domain.Vm;
@@ -54,10 +52,8 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
+import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-import com.google.inject.Inject;
import com.jamesmurty.utils.XMLBuilder;
/**
@@ -73,21 +69,21 @@
protected final BindToStringPayload stringBinder;
protected final ReferenceType defaultNetwork;
protected final FenceMode defaultFenceMode;
- protected final DefaultNetworkNameInTemplate defaultNetworkNameInTemplate;
- protected final VCloudClient client;
+ protected final LoadingCache<URI, VAppTemplate> templateCache;
+ protected final Function<VAppTemplate, String> defaultNetworkNameInTemplate;
@Inject
- public BindInstantiateVAppTemplateParamsToXmlPayload(DefaultNetworkNameInTemplate defaultNetworkNameInTemplate,
- BindToStringPayload stringBinder, @Named(PROPERTY_VCLOUD_XML_NAMESPACE) String ns,
- @Named(PROPERTY_VCLOUD_XML_SCHEMA) String schema, @Network ReferenceType network,
- @Named(PROPERTY_VCLOUD_DEFAULT_FENCEMODE) String fenceMode, VCloudClient client) {
+ public BindInstantiateVAppTemplateParamsToXmlPayload(LoadingCache<URI, VAppTemplate> templateCache,
+ @Network Function<VAppTemplate, String> defaultNetworkNameInTemplate, BindToStringPayload stringBinder,
+ @Named(PROPERTY_VCLOUD_XML_NAMESPACE) String ns, @Named(PROPERTY_VCLOUD_XML_SCHEMA) String schema,
+ @Network ReferenceType network, FenceMode fenceMode) {
+ this.templateCache = templateCache;
this.defaultNetworkNameInTemplate = defaultNetworkNameInTemplate;
this.ns = ns;
this.schema = schema;
this.stringBinder = stringBinder;
this.defaultNetwork = network;
- this.defaultFenceMode = FenceMode.fromValue(fenceMode);
- this.client = client;
+ this.defaultFenceMode = fenceMode;
}
@Override
@@ -97,36 +93,29 @@
GeneratedHttpRequest<?> gRequest = (GeneratedHttpRequest<?>) request;
checkState(gRequest.getArgs() != null, "args should be initialized at this point");
String name = checkNotNull(postParams.remove("name"), "name");
- final URI template = URI.create(checkNotNull(postParams.remove("template"), "template"));
-
- boolean deploy = true;
- boolean powerOn = true;
- Boolean customizeOnInstantiate = null;
+ URI template = URI.create(checkNotNull(postParams.remove("template"), "template"));
Set<NetworkConfig> networkConfig = null;
- NetworkConfigDecorator networknetworkConfigDecorator = new NetworkConfigDecorator(template,
+ NetworkConfigDecorator networkConfigDecorator = new NetworkConfigDecorator(templateCache.getUnchecked(template),
defaultNetwork.getHref(), defaultFenceMode, defaultNetworkNameInTemplate);
InstantiateVAppTemplateOptions options = findOptionsInArgsOrNull(gRequest);
if (options != null) {
if (options.getNetworkConfig().size() > 0)
- networkConfig = Sets.newLinkedHashSet(Iterables.transform(options.getNetworkConfig(),
- networknetworkConfigDecorator));
- deploy = ifNullDefaultTo(options.shouldDeploy(), deploy);
- powerOn = ifNullDefaultTo(options.shouldPowerOn(), powerOn);
- customizeOnInstantiate = options.shouldCustomizeOnInstantiate();
+ networkConfig = ImmutableSet
+ .copyOf(transform(options.getNetworkConfig(), networkConfigDecorator));
+ } else {
+ options = new InstantiateVAppTemplateOptions();
}
if (networkConfig == null)
- networkConfig = ImmutableSet.of(networknetworkConfigDecorator.apply(null));
+ networkConfig = ImmutableSet.of(networkConfigDecorator.apply(null));
try {
- return stringBinder.bindToRequest(
- request,
- generateXml(name, options.getDescription(), deploy, powerOn, template, networkConfig,
- customizeOnInstantiate));
+ return stringBinder.bindToRequest(request, generateXml(name, options.getDescription(), options.shouldDeploy(),
+ options.shouldPowerOn(), template, networkConfig));
} catch (ParserConfigurationException e) {
throw new RuntimeException(e);
} catch (FactoryConfigurationError e) {
@@ -139,9 +128,9 @@
@VisibleForTesting
Set<Vm> ifCustomizationScriptIsSetGetVmsInTemplate(String customizationScript, final URI template) {
- Set<Vm> vms = Sets.newLinkedHashSet();
+ Set<Vm> vms = ImmutableSet.of();
if (customizationScript != null) {
- VAppTemplate vAppTemplate = client.getVAppTemplateClient().getVAppTemplate(template);
+ VAppTemplate vAppTemplate = templateCache.getUnchecked(template);
checkArgument(vAppTemplate != null, "vAppTemplate %s not found!", template);
vms = vAppTemplate.getChildren();
checkArgument(vms.size() > 0, "no vms found in vAppTemplate %s", vAppTemplate);
@@ -150,13 +139,13 @@
}
protected static final class NetworkConfigDecorator implements Function<NetworkConfig, NetworkConfig> {
- private final URI template;
+ private final VAppTemplate template;
private final URI defaultNetwork;
private final FenceMode defaultFenceMode;
- private final DefaultNetworkNameInTemplate defaultNetworkNameInTemplate;
+ private final Function<VAppTemplate, String> defaultNetworkNameInTemplate;
- protected NetworkConfigDecorator(URI template, URI defaultNetwork, FenceMode defaultFenceMode,
- DefaultNetworkNameInTemplate defaultNetworkNameInTemplate) {
+ protected NetworkConfigDecorator(VAppTemplate template, URI defaultNetwork, FenceMode defaultFenceMode,
+ Function<VAppTemplate, String> defaultNetworkNameInTemplate) {
this.template = checkNotNull(template, "template");
this.defaultNetwork = checkNotNull(defaultNetwork, "defaultNetwork");
this.defaultFenceMode = checkNotNull(defaultFenceMode, "defaultFenceMode");
@@ -169,47 +158,22 @@
return new NetworkConfig(defaultNetworkNameInTemplate.apply(template), defaultNetwork, defaultFenceMode);
URI network = ifNullDefaultTo(from.getParentNetwork(), defaultNetwork);
FenceMode fenceMode = ifNullDefaultTo(from.getFenceMode(), defaultFenceMode);
+ // using conditional statement instead of ifNullDefaultTo so that we lazy invoke the
+ // function, as it is an expensive one.
String networkName = from.getNetworkName() != null ? from.getNetworkName() : defaultNetworkNameInTemplate
- .apply(template);
+ .apply(template);
return new NetworkConfig(networkName, network, fenceMode);
}
}
- @Singleton
- public static class DefaultNetworkNameInTemplate implements Function<URI, String> {
- @Resource
- protected Logger logger = Logger.NULL;
-
- private final VCloudClient client;
-
- @Inject
- DefaultNetworkNameInTemplate(VCloudClient client) {
- this.client = client;
- }
-
- @Override
- public String apply(URI template) {
- String networkName;
- VAppTemplate vAppTemplate = client.getVAppTemplateClient().getVAppTemplate(template);
- checkArgument(vAppTemplate != null, "vAppTemplate %s not found!", template);
- Set<org.jclouds.ovf.Network> networks = vAppTemplate.getNetworkSection().getNetworks();
- checkArgument(networks.size() > 0, "no networks found in vAppTemplate %s", vAppTemplate);
- if (networks.size() > 1)
- logger.warn("multiple networks found for %s, choosing first from: %s", vAppTemplate.getName(), networks);
- networkName = Iterables.get(networks, 0).getName();
- return networkName;
- }
- }
-
protected String generateXml(String name, @Nullable String description, boolean deploy, boolean powerOn,
- URI template, Iterable<NetworkConfig> networkConfig, @Nullable Boolean customizeOnInstantiate)
+ URI template, Iterable<NetworkConfig> networkConfig)
throws ParserConfigurationException, FactoryConfigurationError, TransformerException {
XMLBuilder rootBuilder = buildRoot(name).a("deploy", deploy + "").a("powerOn", powerOn + "");
if (description != null)
rootBuilder.e("Description").t(description);
XMLBuilder instantiationParamsBuilder = rootBuilder.e("InstantiationParams");
addNetworkConfig(instantiationParamsBuilder, networkConfig);
- addCustomizationConfig(instantiationParamsBuilder, customizeOnInstantiate);
rootBuilder.e("Source").a("href", template.toASCIIString());
rootBuilder.e("AllEULAsAccepted").t("true");
@@ -218,15 +182,6 @@
return rootBuilder.asString(outputProperties);
}
- protected void addCustomizationConfig(XMLBuilder instantiationParamsBuilder, Boolean customizeOnInstantiate) {
- if (customizeOnInstantiate != null) {
- // XMLBuilder customizationSectionBuilder =
- // instantiationParamsBuilder.e("CustomizationSection");
- // customizationSectionBuilder.e("ovf:Info").t("VApp template customization section");
- // customizationSectionBuilder.e("CustomizeOnInstantiate").t(customizeOnInstantiate.toString());
- }
- }
-
protected void addNetworkConfig(XMLBuilder instantiationParamsBuilder,
Iterable<NetworkConfig> networkConfig) {
XMLBuilder networkConfigBuilder = instantiationParamsBuilder.e("NetworkConfigSection");
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceDependenciesModule.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceDependenciesModule.java
index 3198433..c77c3fb 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceDependenciesModule.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceDependenciesModule.java
@@ -45,9 +45,13 @@
import org.jclouds.vcloud.compute.options.VCloudTemplateOptions;
import org.jclouds.vcloud.compute.strategy.VCloudComputeServiceAdapter;
import org.jclouds.vcloud.domain.Org;
+import org.jclouds.vcloud.domain.ReferenceType;
import org.jclouds.vcloud.domain.Status;
import org.jclouds.vcloud.domain.VApp;
import org.jclouds.vcloud.domain.VAppTemplate;
+import org.jclouds.vcloud.domain.network.FenceMode;
+import org.jclouds.vcloud.domain.network.NetworkConfig;
+import org.jclouds.vcloud.endpoints.Network;
import org.jclouds.vcloud.functions.VAppTemplatesInOrg;
import com.google.common.annotations.VisibleForTesting;
@@ -110,6 +114,14 @@
}).to((Class) IdentityFunction.class);
}
+
+ @Provides
+ @Singleton
+ public NetworkConfig networkConfig(@Network ReferenceType network, FenceMode defaultFenceMode) {
+ return new NetworkConfig(network.getName(), network.getHref(), defaultFenceMode);
+ }
+
+
@Singleton
public static class DefaultVDC implements Supplier<Location> {
private final Supplier<Set<? extends Location>> locationsSupplier;
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/HardwareForVAppTemplate.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/HardwareForVAppTemplate.java
index 2da38fe..ac14181 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/HardwareForVAppTemplate.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/HardwareForVAppTemplate.java
@@ -30,7 +30,6 @@
import org.jclouds.logging.Logger;
import org.jclouds.ovf.Envelope;
import org.jclouds.ovf.VirtualHardwareSection;
-import org.jclouds.vcloud.VCloudClient;
import org.jclouds.vcloud.domain.VAppTemplate;
import com.google.common.base.Function;
@@ -45,46 +44,39 @@
@Resource
protected Logger logger = Logger.NULL;
- private final VCloudClient client;
+ private final Function<VAppTemplate, Envelope> templateToEnvelope;
private final FindLocationForResource findLocationForResource;
private final VCloudHardwareBuilderFromResourceAllocations rasdToHardwareBuilder;
@Inject
- protected HardwareForVAppTemplate(VCloudClient client, FindLocationForResource findLocationForResource,
+ protected HardwareForVAppTemplate(Function<VAppTemplate, Envelope> templateToEnvelope,
+ FindLocationForResource findLocationForResource,
VCloudHardwareBuilderFromResourceAllocations rasdToHardwareBuilder) {
- this.client = checkNotNull(client, "client");
+ this.templateToEnvelope = checkNotNull(templateToEnvelope, "templateToEnvelope");
this.findLocationForResource = checkNotNull(findLocationForResource, "findLocationForResource");
this.rasdToHardwareBuilder = checkNotNull(rasdToHardwareBuilder, "rasdToHardwareBuilder");
}
-
@Override
public Hardware apply(VAppTemplate from) {
checkNotNull(from, "VAppTemplate");
- if (!from.isOvfDescriptorUploaded()) {
- logger.warn("cannot parse hardware as ovf descriptor for %s is not uploaded", from);
- return null;
- }
+ Envelope ovf = templateToEnvelope.apply(from);
- Envelope ovf = client.getVAppTemplateClient().getOvfEnvelopeForVAppTemplate(from.getHref());
- if (ovf == null) {
- logger.warn("cannot parse hardware as no ovf envelope found for %s", from);
- return null;
- }
- if (ovf.getVirtualSystem().getVirtualHardwareSections().size() == 0) {
- logger.warn("cannot parse hardware for %s as no hardware sections exist in ovf %s", ovf);
- return null;
- }
if (ovf.getVirtualSystem().getVirtualHardwareSections().size() > 1) {
logger.warn("multiple hardware choices found. using first", ovf);
}
VirtualHardwareSection hardware = Iterables.get(ovf.getVirtualSystem().getVirtualHardwareSections(), 0);
HardwareBuilder builder = rasdToHardwareBuilder.apply(hardware.getItems());
- builder.location(findLocationForResource.apply(checkNotNull(from.getVDC(), "VDC")));
+ if (from.getVDC() != null) {
+ builder.location(findLocationForResource.apply(from.getVDC()));
+ } else {
+ // otherwise, it could be in a public catalog, which is not assigned to a VDC
+ }
builder.ids(from.getHref().toASCIIString()).name(from.getName()).supportsImage(
ImagePredicates.idEquals(from.getHref().toASCIIString()));
return builder.build();
+
}
protected String getName(String name) {
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ImageForVAppTemplate.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ImageForVAppTemplate.java
index 7cd0606..3bab981 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ImageForVAppTemplate.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ImageForVAppTemplate.java
@@ -20,14 +20,17 @@
import static com.google.common.base.Preconditions.checkNotNull;
+import javax.annotation.Resource;
import javax.inject.Inject;
+import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.compute.domain.CIMOperatingSystem;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.ImageBuilder;
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.logging.Logger;
import org.jclouds.ovf.Envelope;
-import org.jclouds.vcloud.VCloudClient;
import org.jclouds.vcloud.domain.VAppTemplate;
import com.google.common.base.Function;
@@ -37,25 +40,36 @@
*/
@Singleton
public class ImageForVAppTemplate implements Function<VAppTemplate, Image> {
- private final VCloudClient client;
+
+ @Resource
+ @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+ public Logger logger = Logger.NULL;
+
+ private final Function<VAppTemplate, Envelope> templateToEnvelope;
private final FindLocationForResource findLocationForResource;
@Inject
- protected ImageForVAppTemplate(VCloudClient client, FindLocationForResource findLocationForResource) {
- this.client = checkNotNull(client, "client");
+ protected ImageForVAppTemplate(Function<VAppTemplate, Envelope> templateToEnvelope,
+ FindLocationForResource findLocationForResource) {
+ this.templateToEnvelope = checkNotNull(templateToEnvelope, "templateToEnvelope");
this.findLocationForResource = checkNotNull(findLocationForResource, "findLocationForResource");
}
-
@Override
public Image apply(VAppTemplate from) {
+ checkNotNull(from, "VAppTemplate");
+ Envelope ovf = templateToEnvelope.apply(from);
+
ImageBuilder builder = new ImageBuilder();
builder.ids(from.getHref().toASCIIString());
builder.uri(from.getHref());
builder.name(from.getName());
- builder.location(findLocationForResource.apply(checkNotNull(from.getVDC(), "VDC")));
+ if (from.getVDC() != null) {
+ builder.location(findLocationForResource.apply(from.getVDC()));
+ } else {
+ // otherwise, it could be in a public catalog, which is not assigned to a VDC
+ }
builder.description(from.getDescription() != null ? from.getDescription() : from.getName());
- Envelope ovf = client.getVAppTemplateClient().getOvfEnvelopeForVAppTemplate(from.getHref());
builder.operatingSystem(CIMOperatingSystem.toComputeOs(ovf));
return builder.build();
}
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/VAppToNodeMetadata.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/VAppToNodeMetadata.java
index 58fe908..8563585 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/VAppToNodeMetadata.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/VAppToNodeMetadata.java
@@ -72,6 +72,7 @@
builder.ids(from.getHref().toASCIIString());
builder.uri(from.getHref());
builder.name(from.getName());
+ builder.hostname(from.getName());
builder.location(findLocationForResourceInVDC.apply(from.getVDC()));
builder.group(parseGroupFromName(from.getName()));
builder.operatingSystem(toComputeOs(from, null));
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException.java
new file mode 100644
index 0000000..a72b84a
--- /dev/null
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException.java
@@ -0,0 +1,79 @@
+/**
+ * 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.vcloud.compute.functions;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.net.URI;
+import java.util.concurrent.ExecutionException;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.logging.Logger;
+import org.jclouds.ovf.Envelope;
+import org.jclouds.vcloud.domain.VAppTemplate;
+
+import com.google.common.base.Function;
+import com.google.common.cache.LoadingCache;
+
+/**
+ * @author Adrian Cole
+ */
+@Singleton
+public class ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException implements
+ Function<VAppTemplate, Envelope> {
+
+ @Resource
+ protected Logger logger = Logger.NULL;
+
+ private final LoadingCache<URI, Envelope> envelopes;
+
+ @Inject
+ protected ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException(LoadingCache<URI, Envelope> envelopes) {
+ this.envelopes = checkNotNull(envelopes, "envelopes");
+ }
+
+ @Override
+ public Envelope apply(VAppTemplate from) {
+ checkArgument(from.getChildren().size() == 1, "multiple vms are not supported: %s", from);
+
+ checkArgument(from.getNetworkSection().getNetworks().size() == 1,
+ "multiple network connections are not supported: %s", from);
+
+ checkArgument(from.isOvfDescriptorUploaded(), "ovf descriptor is not uploaded: %s", from);
+ Envelope ovf = getOVFForVAppTemplateAndValidate(from);
+ return ovf;
+ }
+
+ private Envelope getOVFForVAppTemplateAndValidate(VAppTemplate from) throws IllegalArgumentException {
+ Envelope ovf;
+ try {
+ ovf = envelopes.get(from.getHref());
+ checkArgument(ovf.getVirtualSystem().getVirtualHardwareSections().size() > 0,
+ "no hardware sections exist in ovf %s", ovf);
+ } catch (ExecutionException e) {
+ throw new IllegalArgumentException("no ovf envelope found for: " + from, e);
+ }
+ return ovf;
+ }
+}
+
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn.java
index 6bb0948..823bd76 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn.java
@@ -18,8 +18,14 @@
*/
package org.jclouds.vcloud.compute.strategy;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Predicates.not;
+import static com.google.common.collect.Iterables.find;
+import static com.google.common.collect.Iterables.get;
+import static org.jclouds.Constants.PROPERTY_BUILD_VERSION;
import static org.jclouds.compute.util.ComputeServiceUtils.getCores;
import static org.jclouds.vcloud.compute.util.VCloudComputeUtils.getCredentialsFrom;
+import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.addNetworkConfig;
import java.net.URI;
@@ -31,7 +37,11 @@
import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.javax.annotation.Nullable;
import org.jclouds.logging.Logger;
+import org.jclouds.ovf.Network;
+import org.jclouds.predicates.validators.DnsNameValidator;
+import org.jclouds.vcloud.TaskStillRunningException;
import org.jclouds.vcloud.VCloudClient;
import org.jclouds.vcloud.compute.options.VCloudTemplateOptions;
import org.jclouds.vcloud.domain.GuestCustomizationSection;
@@ -39,14 +49,16 @@
import org.jclouds.vcloud.domain.NetworkConnectionSection;
import org.jclouds.vcloud.domain.Task;
import org.jclouds.vcloud.domain.VApp;
+import org.jclouds.vcloud.domain.VAppTemplate;
import org.jclouds.vcloud.domain.Vm;
import org.jclouds.vcloud.domain.NetworkConnectionSection.Builder;
import org.jclouds.vcloud.domain.network.IpAddressAllocationMode;
+import org.jclouds.vcloud.domain.network.NetworkConfig;
import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions;
-import com.google.common.base.Function;
import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableSet;
/**
* @author Adrian Cole
@@ -59,101 +71,218 @@
protected final VCloudClient client;
protected final Predicate<URI> successTester;
+ protected final LoadingCache<URI, VAppTemplate> vAppTemplates;
+ protected final NetworkConfig defaultNetworkConfig;
+ protected final String buildVersion;
@Inject
- protected InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn(Predicate<URI> successTester,
- VCloudClient client) {
+ protected InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn(VCloudClient client,
+ Predicate<URI> successTester, LoadingCache<URI, VAppTemplate> vAppTemplates,
+ NetworkConfig defaultNetworkConfig, @Named(PROPERTY_BUILD_VERSION) String buildVersion) {
this.client = client;
this.successTester = successTester;
+ this.vAppTemplates = vAppTemplates;
+ this.defaultNetworkConfig = defaultNetworkConfig;
+ this.buildVersion = buildVersion;
}
- public NodeAndInitialCredentials<VApp> createNodeWithGroupEncodedIntoName(String tag, String name, Template template) {
- InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions();
+ // TODO: filtering on "none" is a hack until we can filter on
+ // vAppTemplate.getNetworkConfigSection().getNetworkConfigs() where
+ // name = getChildren().NetworkConnectionSection.connection where ipallocationmode == none
+ Predicate<Network> networkWithNoIpAllocation = new Predicate<Network>() {
+
+ @Override
+ public boolean apply(Network input) {
+ return "none".equals(input.getName());
+ }
+
+ };
+
+ /**
+ * per john ellis at bluelock, vCloud Director 1.5 is more strict than earlier versions.
+ * <p/>
+ * It appears to be 15 characters to match Windows' hostname limitation. Must be alphanumeric, at
+ * least one non-number character and hyphens and underscores are the only non-alpha character
+ * allowed.
+ */
+ public static enum ComputerNameValidator {
+ INSTANCE;
+
+ private DnsNameValidator validator;
+
+ ComputerNameValidator(){
+ this.validator = new DnsNameValidator(3, 15);
+ }
+
+ public void validate(@Nullable String t) throws IllegalArgumentException {
+ this.validator.validate(t);
+ }
+
+ }
+
+ public NodeAndInitialCredentials<VApp> createNodeWithGroupEncodedIntoName(String group, String name, Template template) {
+ // no sense waiting until failures occur later
+ ComputerNameValidator.INSTANCE.validate(name);
+
+ URI templateId = URI.create(template.getImage().getId());
+
+ VAppTemplate vAppTemplate = vAppTemplates.getUnchecked(templateId);
+
+ if (vAppTemplate.getChildren().size() > 1)
+ throw new UnsupportedOperationException("we currently do not support multiple vms in a vAppTemplate "
+ + vAppTemplate);
+
+ if (vAppTemplate.getNetworkSection().getNetworks().size() > 1)
+ throw new UnsupportedOperationException(
+ "we currently do not support multiple network connections in a vAppTemplate " + vAppTemplate);
+
+ Network networkToConnect = get(vAppTemplate.getNetworkSection().getNetworks(), 0);
+
+ NetworkConfig config;
+ // if we only have a disconnected network, let's add a new section for the upstream
+ // TODO: remove the disconnected entry
+ if (networkWithNoIpAllocation.apply(networkToConnect))
+ config = defaultNetworkConfig;
+ else
+ config = defaultNetworkConfig.toBuilder().networkName(networkToConnect.getName()).build();
+
+ // note that in VCD 1.5, the network name after instantiation will be the same as the parent
+ InstantiateVAppTemplateOptions options = addNetworkConfig(config);
// TODO make disk size specifiable
// disk((long) ((template.getHardware().getVolumes().get(0).getSize()) *
// 1024 * 1024l));
String customizationScript = VCloudTemplateOptions.class.cast(template.getOptions()).getCustomizationScript();
- IpAddressAllocationMode ipAddressAllocationMode = VCloudTemplateOptions.class.cast(template.getOptions())
+ IpAddressAllocationMode ipAllocationMode = VCloudTemplateOptions.class.cast(template.getOptions())
.getIpAddressAllocationMode();
- options.description(VCloudTemplateOptions.class.cast(template.getOptions()).getDescription());
- options.customizeOnInstantiate(false);
+ String description = VCloudTemplateOptions.class.cast(template.getOptions()).getDescription();
+ if (description == null)
+ description = vAppTemplate.getName();
+
+ options.description(description);
options.deploy(false);
options.powerOn(false);
- if (!template.getOptions().shouldBlockUntilRunning())
- options.block(false);
-
URI VDC = URI.create(template.getLocation().getId());
- URI templateId = URI.create(template.getImage().getId());
logger.debug(">> instantiating vApp vDC(%s) template(%s) name(%s) options(%s) ", VDC, templateId, name, options);
VApp vAppResponse = client.getVAppTemplateClient().createVAppInVDCByInstantiatingTemplate(name, VDC, templateId,
options);
- waitForTask(vAppResponse.getTasks().get(0), vAppResponse);
+ waitForTask(vAppResponse.getTasks().get(0));
logger.debug("<< instantiated VApp(%s)", vAppResponse.getName());
- // note customization is a serial concern at the moment
- Vm vm = Iterables.get(client.getVAppClient().getVApp(vAppResponse.getHref()).getChildren(), 0);
- if (customizationScript != null) {
- logger.trace(">> updating customization vm(%s) ", vm.getName());
- waitForTask(updateVmWithCustomizationScript(vm, customizationScript), vAppResponse);
- logger.trace("<< updated customization vm(%s) ", vm.getName());
- }
- if (ipAddressAllocationMode != null) {
- logger.trace(">> updating ipAddressAllocationMode(%s) vm(%s) ", ipAddressAllocationMode, vm.getName());
- waitForTask(updateVmWithIpAddressAllocationMode(vm, ipAddressAllocationMode), vAppResponse);
- logger.trace("<< updated ipAddressAllocationMode vm(%s) ", vm.getName());
- }
+ // vm data is available after instantiate completes
+ vAppResponse = client.getVAppClient().getVApp(vAppResponse.getHref());
+
+ // per above check, we know there is only a single VM
+ Vm vm = get(vAppResponse.getChildren(), 0);
+
+ // note we cannot do tasks in parallel or VCD will throw "is busy" errors
+
+ // note we must do this before any other customizations as there is a dependency on
+ // valid naming conventions before you can perform commands such as updateCPUCount
+ logger.trace(">> updating customization vm(%s) name->(%s)", vm.getName(), name);
+ waitForTask(updateVmWithNameAndCustomizationScript(vm, name, customizationScript));
+ logger.trace("<< updated customization vm(%s)", name);
+
+ ensureVmHasAllocationModeOrPooled(vAppResponse, ipAllocationMode);
+
int cpuCount = new Double(getCores(template.getHardware())).intValue();
- logger.trace(">> updating cpuCount(%d) vm(%s) ", cpuCount, vm.getName());
- waitForTask(updateCPUCountOfVm(vm, cpuCount), vAppResponse);
- logger.trace("<< updated cpuCount vm(%s) ", vm.getName());
+ logger.trace(">> updating cpuCount(%d) vm(%s)", cpuCount, vm.getName());
+ waitForTask(updateCPUCountOfVm(vm, cpuCount));
+ logger.trace("<< updated cpuCount vm(%s)", vm.getName());
int memoryMB = template.getHardware().getRam();
- logger.trace(">> updating memoryMB(%d) vm(%s) ", memoryMB, vm.getName());
- waitForTask(updateMemoryMBOfVm(vm, memoryMB), vAppResponse);
- logger.trace("<< updated memoryMB vm(%s) ", vm.getName());
- logger.trace(">> deploying and powering on vApp(%s) ", vAppResponse.getName());
- vAppResponse = blockOnDeployAndPowerOnIfConfigured(options, vAppResponse, client.getVAppClient()
- .deployAndPowerOnVApp(vAppResponse.getHref()));
+ logger.trace(">> updating memoryMB(%d) vm(%s)", memoryMB, vm.getName());
+ waitForTask(updateMemoryMBOfVm(vm, memoryMB));
+ logger.trace("<< updated memoryMB vm(%s)", vm.getName());
+ logger.trace(">> deploying vApp(%s)", vAppResponse.getName());
+ waitForTask(client.getVAppClient().deployVApp(vAppResponse.getHref()));
+ logger.trace("<< deployed vApp(%s)", vAppResponse.getName());
+
+ // only after deploy is the password valid
+ vAppResponse = client.getVAppClient().getVApp(vAppResponse.getHref());
+
+ logger.trace(">> powering on vApp(%s)", vAppResponse.getName());
+ client.getVAppClient().powerOnVApp(vAppResponse.getHref());
+
return new NodeAndInitialCredentials<VApp>(vAppResponse, vAppResponse.getHref().toASCIIString(),
getCredentialsFrom(vAppResponse));
}
- public void waitForTask(Task task, VApp vAppResponse) {
+ public void waitForTask(Task task) {
if (!successTester.apply(task.getHref())) {
- throw new RuntimeException(String.format("failed to %s %s: %s", task.getName(), vAppResponse.getName(), task));
+ throw new TaskStillRunningException(task);
}
}
- public Task updateVmWithCustomizationScript(Vm vm, String customizationScript) {
+ /**
+ * Naming constraints modifying a VM on a VApp in vCloud Director (at least v1.5) can be more
+ * strict than those in a vAppTemplate. For example, while it is possible to instantiate a
+ * vAppTemplate with a VM named (incorrectly) {@code Ubuntu_10.04}, you must change the name to a
+ * valid (alphanumeric underscore) name before you can update it.
+ */
+ public Task updateVmWithNameAndCustomizationScript(Vm vm, String name, @Nullable String customizationScript) {
GuestCustomizationSection guestConfiguration = vm.getGuestCustomizationSection();
- // TODO: determine if the server version is beyond 1.0.0, and if so append
- // to, but
- // not overwrite the customization script. In version 1.0.0, the api
- // returns a script that
- // loses newlines.
- guestConfiguration.setCustomizationScript(customizationScript);
+ guestConfiguration.setComputerName(name);
+ if (customizationScript != null) {
+ // In version 1.0.0, the api returns a script that loses newlines, so we cannot append to a
+ // customization script.
+ // TODO: parameterize whether to overwrite or append existing customization
+ if (!buildVersion.startsWith("1.0.0") && !"".endsWith(buildVersion)
+ && guestConfiguration.getCustomizationScript() != null)
+ customizationScript = guestConfiguration.getCustomizationScript() + "\n" + customizationScript;
+
+ guestConfiguration.setCustomizationScript(customizationScript);
+ }
return client.getVmClient().updateGuestCustomizationOfVm(guestConfiguration, vm.getHref());
}
- public Task updateVmWithIpAddressAllocationMode(Vm vm, final IpAddressAllocationMode ipAddressAllocationMode) {
+ public void ensureVmHasAllocationModeOrPooled(VApp vApp, @Nullable IpAddressAllocationMode ipAllocationMode) {
+ Network networkToConnect = find(vApp.getNetworkSection().getNetworks(), not(networkWithNoIpAllocation));
+
+ Vm vm = get(vApp.getChildren(), 0);
+
NetworkConnectionSection net = vm.getNetworkConnectionSection();
- Builder builder = net.toBuilder();
- builder.connections(Iterables.transform(net.getConnections(),
- new Function<NetworkConnection, NetworkConnection>() {
+ checkArgument(net.getConnections().size() > 0, "no connections on vm %s", vm);
- @Override
- public NetworkConnection apply(NetworkConnection arg0) {
- return arg0.toBuilder().connected(true).ipAddressAllocationMode(ipAddressAllocationMode).build();
- }
+ NetworkConnection toConnect = findWithPoolAllocationOrFirst(net);
- }));
- return client.getVmClient().updateNetworkConnectionOfVm(builder.build(), vm.getHref());
+ if (ipAllocationMode == null)
+ ipAllocationMode = toConnect.getIpAddressAllocationMode();
+
+ // make sure that we are in fact allocating ips
+ if (ipAllocationMode == IpAddressAllocationMode.NONE)
+ ipAllocationMode = IpAddressAllocationMode.POOL;
+
+ if (toConnect.isConnected() && toConnect.getIpAddressAllocationMode() == ipAllocationMode
+ && toConnect.getNetwork().equals(networkToConnect.getName())) {
+ // then we don't need to change the network settings, and can save a call
+ } else {
+ Builder builder = net.toBuilder();
+ builder.connections(ImmutableSet.of(toConnect.toBuilder().network(networkToConnect.getName()).connected(true)
+ .ipAddressAllocationMode(ipAllocationMode).build()));
+ logger.trace(">> updating networkConnection vm(%s)", vm.getName());
+
+ waitForTask(client.getVmClient().updateNetworkConnectionOfVm(builder.build(), vm.getHref()));
+ logger.trace("<< updated networkConnection vm(%s)", vm.getName());
+
+ }
+
+ }
+
+ private NetworkConnection findWithPoolAllocationOrFirst(NetworkConnectionSection net) {
+ return find(net.getConnections(), new Predicate<NetworkConnection>() {
+
+ @Override
+ public boolean apply(NetworkConnection input) {
+ return input.getIpAddressAllocationMode() == IpAddressAllocationMode.POOL;
+ }
+
+ }, get(net.getConnections(), 0));
}
public Task updateCPUCountOfVm(Vm vm, int cpuCount) {
@@ -163,12 +292,4 @@
public Task updateMemoryMBOfVm(Vm vm, int memoryInMB) {
return client.getVmClient().updateMemoryMBOfVm(memoryInMB, vm.getHref());
}
-
- private VApp blockOnDeployAndPowerOnIfConfigured(InstantiateVAppTemplateOptions options, VApp vAppResponse, Task task) {
- if (options.shouldBlock()) {
- waitForTask(task, vAppResponse);
- logger.debug("<< ready vApp(%s)", vAppResponse.getName());
- }
- return client.getVAppClient().getVApp(vAppResponse.getHref());
- }
}
\ No newline at end of file
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudComputeServiceAdapter.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudComputeServiceAdapter.java
index 1524eeb..5fa129d 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudComputeServiceAdapter.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudComputeServiceAdapter.java
@@ -35,6 +35,9 @@
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.Location;
import org.jclouds.logging.Logger;
+import org.jclouds.ovf.Envelope;
+import org.jclouds.vcloud.TaskInErrorStateException;
+import org.jclouds.vcloud.TaskStillRunningException;
import org.jclouds.vcloud.VCloudClient;
import org.jclouds.vcloud.VCloudMediaType;
import org.jclouds.vcloud.compute.suppliers.OrgAndVDCToLocationSupplier;
@@ -47,9 +50,11 @@
import org.jclouds.vcloud.suppliers.VAppTemplatesSupplier;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
import com.google.common.collect.ImmutableSet.Builder;
/**
@@ -69,18 +74,20 @@
protected final InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn booter;
protected final Supplier<Map<String, Org>> nameToOrg;
protected final Supplier<Set<VAppTemplate>> templates;
+ protected final Function<VAppTemplate, Envelope> templateToEnvelope;
protected final Supplier<Set<? extends Location>> locations;
@Inject
protected VCloudComputeServiceAdapter(VCloudClient client, Predicate<URI> successTester,
InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn booter,
- Supplier<Map<String, Org>> nameToOrg, VAppTemplatesSupplier templates,
- OrgAndVDCToLocationSupplier locations) {
+ Supplier<Map<String, Org>> nameToOrg, VAppTemplatesSupplier templates,
+ Function<VAppTemplate, Envelope> templateToEnvelope, OrgAndVDCToLocationSupplier locations) {
this.client = checkNotNull(client, "client");
this.successTester = checkNotNull(successTester, "successTester");
this.booter = checkNotNull(booter, "booter");
this.nameToOrg = checkNotNull(nameToOrg, "nameToOrg");
this.templates = checkNotNull(templates, "templates");
+ this.templateToEnvelope = checkNotNull(templateToEnvelope, "templateToEnvelope");
this.locations = checkNotNull(locations, "locations");
}
@@ -92,12 +99,29 @@
@Override
public Iterable<VAppTemplate> listHardwareProfiles() {
- return templates.get();
+ return supportedTemplates();
+ }
+
+ private Iterable<VAppTemplate> supportedTemplates() {
+ return Iterables.filter(templates.get(), new Predicate<VAppTemplate>() {
+
+ @Override
+ public boolean apply(VAppTemplate from) {
+ try {
+ templateToEnvelope.apply(from);
+ } catch (IllegalArgumentException e){
+ logger.warn("Unsupported: "+ e.getMessage());
+ return false;
+ }
+ return true;
+ }
+
+ });
}
@Override
public Iterable<VAppTemplate> listImages() {
- return templates.get();
+ return supportedTemplates();
}
@Override
@@ -140,70 +164,79 @@
public VApp getNode(String in) {
URI id = URI.create(in);
return client.getVAppClient().getVApp(id);
-
}
@Override
public void destroyNode(String id) {
URI vappId = URI.create(checkNotNull(id, "node.id"));
- VApp vApp = client.getVAppClient().getVApp(vappId);
-
- waitForPendingTasksToComplete(vApp);
-
- vApp = undeployVAppIfDeployed(vApp);
- deleteVApp(vApp);
- }
-
- void waitForPendingTasksToComplete(VApp vApp) {
- for (Task task : vApp.getTasks())
- waitForTask(task, vApp);
- }
-
- public void waitForTask(Task task, VApp vAppResponse) {
- if (!successTester.apply(task.getHref())) {
- throw new RuntimeException(String.format("failed to %s %s: %s", task.getName(), vAppResponse.getName(), task));
- }
- }
-
- void deleteVApp(VApp vApp) {
- logger.debug(">> deleting vApp(%s)", vApp.getHref());
- waitForTask(client.getVAppClient().deleteVApp(vApp.getHref()), vApp);
- logger.debug("<< deleted vApp(%s)", vApp.getHref());
- }
-
- VApp undeployVAppIfDeployed(VApp vApp) {
+ VApp vApp = cancelAnyRunningTasks(vappId);
if (vApp.getStatus() != Status.OFF) {
+ logger.debug(">> powering off VApp vApp(%s), current status: %s", vApp.getName(), vApp.getStatus());
+ try {
+ waitForTask(client.getVAppClient().powerOffVApp(vApp.getHref()));
+ vApp = client.getVAppClient().getVApp(vApp.getHref());
+ logger.debug("<< %s vApp(%s)", vApp.getStatus(), vApp.getName());
+ } catch (IllegalStateException e) {
+ logger.warn(e, "<< %s vApp(%s)", vApp.getStatus(), vApp.getName());
+ }
logger.debug(">> undeploying vApp(%s), current status: %s", vApp.getName(), vApp.getStatus());
try {
- waitForTask(client.getVAppClient().undeployVApp(vApp.getHref()), vApp);
+ waitForTask(client.getVAppClient().undeployVApp(vApp.getHref()));
vApp = client.getVAppClient().getVApp(vApp.getHref());
logger.debug("<< %s vApp(%s)", vApp.getStatus(), vApp.getName());
} catch (IllegalStateException e) {
logger.warn(e, "<< %s vApp(%s)", vApp.getStatus(), vApp.getName());
}
}
- return vApp;
+ logger.debug(">> deleting vApp(%s)", vApp.getHref());
+ waitForTask(client.getVAppClient().deleteVApp(vApp.getHref()));
+ logger.debug("<< deleted vApp(%s)", vApp.getHref());
+ }
+
+ VApp waitForPendingTasksToComplete(URI vappId) {
+ VApp vApp = client.getVAppClient().getVApp(vappId);
+ if (vApp.getTasks().size() == 0)
+ return vApp;
+ for (Task task : vApp.getTasks())
+ waitForTask(task);
+ return client.getVAppClient().getVApp(vappId);
+ }
+
+ VApp cancelAnyRunningTasks(URI vappId) {
+ VApp vApp = client.getVAppClient().getVApp(vappId);
+ if (vApp.getTasks().size() == 0)
+ return vApp;
+ for (Task task : vApp.getTasks()) {
+ try {
+ client.getTaskClient().cancelTask(task.getHref());
+ waitForTask(task);
+ } catch (TaskInErrorStateException e) {
+ }
+ }
+ return client.getVAppClient().getVApp(vappId);
+
+ }
+
+ public void waitForTask(Task task) {
+ if (!successTester.apply(task.getHref()))
+ throw new TaskStillRunningException(task);
}
@Override
public void rebootNode(String in) {
URI id = URI.create(checkNotNull(in, "node.id"));
- Task task = client.getVAppClient().resetVApp(id);
- successTester.apply(task.getHref());
-
+ waitForTask(client.getVAppClient().resetVApp(id));
}
@Override
public void resumeNode(String in) {
URI id = URI.create(checkNotNull(in, "node.id"));
- Task task = client.getVAppClient().powerOnVApp(id);
- successTester.apply(task.getHref());
+ waitForTask(client.getVAppClient().powerOnVApp(id));
}
@Override
public void suspendNode(String in) {
URI id = URI.create(checkNotNull(in, "node.id"));
- Task task = client.getVAppClient().powerOffVApp(id);
- successTester.apply(task.getHref());
+ waitForTask(client.getVAppClient().powerOffVApp(id));
}
-}
\ No newline at end of file
+}
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/util/VCloudComputeUtils.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/util/VCloudComputeUtils.java
index 26d73bc..93f197d 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/util/VCloudComputeUtils.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/util/VCloudComputeUtils.java
@@ -77,10 +77,6 @@
public static LoginCredentials getCredentialsFrom(Vm vm) {
LoginCredentials.Builder builder = LoginCredentials.builder();
- builder.user("root");
- if (vm.getOperatingSystemSection() != null && vm.getOperatingSystemSection().getDescription() != null
- && vm.getOperatingSystemSection().getDescription().indexOf("Windows") >= 0)
- builder.user("Administrator");
if (vm.getGuestCustomizationSection() != null)
builder.password(vm.getGuestCustomizationSection().getAdminPassword());
return builder.build();
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/config/VCloudRestClientModule.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/config/VCloudRestClientModule.java
index c54cee2..e40ed27 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/config/VCloudRestClientModule.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/config/VCloudRestClientModule.java
@@ -20,20 +20,24 @@
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Predicates.notNull;
+import static com.google.common.base.Suppliers.compose;
import static com.google.common.base.Throwables.propagate;
import static com.google.common.collect.Iterables.concat;
+import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.getLast;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Maps.transformValues;
import static com.google.common.collect.Maps.uniqueIndex;
import static org.jclouds.Constants.PROPERTY_API_VERSION;
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
+import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_FENCEMODE;
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_TIMEOUT_TASK_COMPLETED;
import java.net.URI;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.SortedMap;
+import java.util.Map.Entry;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -50,6 +54,7 @@
import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError;
+import org.jclouds.ovf.Envelope;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.rest.AsyncClientFactory;
import org.jclouds.rest.AuthorizationException;
@@ -61,6 +66,7 @@
import org.jclouds.vcloud.VCloudToken;
import org.jclouds.vcloud.VCloudVersionsAsyncClient;
import org.jclouds.vcloud.compute.functions.FindLocationForResource;
+import org.jclouds.vcloud.compute.functions.ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException;
import org.jclouds.vcloud.domain.Catalog;
import org.jclouds.vcloud.domain.CatalogItem;
import org.jclouds.vcloud.domain.Org;
@@ -68,6 +74,8 @@
import org.jclouds.vcloud.domain.VAppTemplate;
import org.jclouds.vcloud.domain.VCloudSession;
import org.jclouds.vcloud.domain.VDC;
+import org.jclouds.vcloud.domain.network.FenceMode;
+import org.jclouds.vcloud.endpoints.Network;
import org.jclouds.vcloud.endpoints.OrgList;
import org.jclouds.vcloud.features.CatalogAsyncClient;
import org.jclouds.vcloud.features.CatalogClient;
@@ -89,22 +97,25 @@
import org.jclouds.vcloud.functions.AllCatalogItemsInOrg;
import org.jclouds.vcloud.functions.AllCatalogsInOrg;
import org.jclouds.vcloud.functions.AllVDCsInOrg;
+import org.jclouds.vcloud.functions.DefaultNetworkNameInTemplate;
import org.jclouds.vcloud.functions.OrgsForLocations;
import org.jclouds.vcloud.functions.OrgsForNames;
import org.jclouds.vcloud.functions.VAppTemplatesForCatalogItems;
import org.jclouds.vcloud.handlers.ParseVCloudErrorFromHttpResponse;
import org.jclouds.vcloud.internal.VCloudLoginAsyncClient;
+import org.jclouds.vcloud.loaders.OVFLoader;
+import org.jclouds.vcloud.loaders.VAppTemplateLoader;
import org.jclouds.vcloud.predicates.TaskSuccess;
import org.jclouds.vcloud.xml.ovf.VCloudResourceAllocationSettingDataHandler;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
-import static com.google.common.base.Predicates.*;
import com.google.common.base.Supplier;
-import static com.google.common.base.Suppliers.*;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
-import static com.google.common.collect.Iterables.*;
import com.google.inject.Injector;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
@@ -192,6 +203,27 @@
bind(new TypeLiteral<Function<Org, Iterable<CatalogItem>>>() {
}).to(new TypeLiteral<AllCatalogItemsInOrg>() {
});
+
+ bindCacheLoaders();
+
+ bind(new TypeLiteral<Function<VAppTemplate, String>>() {
+ }).annotatedWith(Network.class).to(new TypeLiteral<DefaultNetworkNameInTemplate>() {
+ });
+
+ bind(new TypeLiteral<Function<VAppTemplate, Envelope>>() {
+ }).to(new TypeLiteral<ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException>() {
+ });
+
+ }
+
+ protected void bindCacheLoaders() {
+ bind(new TypeLiteral<CacheLoader<URI, VAppTemplate>>() {
+ }).to(new TypeLiteral<VAppTemplateLoader>() {
+ });
+
+ bind(new TypeLiteral<CacheLoader<URI, Envelope>>() {
+ }).to(new TypeLiteral<OVFLoader>() {
+ });
}
@Provides
@@ -486,7 +518,26 @@
return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<String, Map<String, Map<String, org.jclouds.vcloud.domain.CatalogItem>>>>(
authException, seconds, supplier);
}
+
+
+ @Provides
+ @Singleton
+ protected FenceMode defaultFenceMode(@Named(PROPERTY_VCLOUD_DEFAULT_FENCEMODE) String fenceMode){
+ return FenceMode.fromValue(fenceMode);
+ }
+
+ @Provides
+ @Singleton
+ protected LoadingCache<URI, VAppTemplate> vAppTemplates(CacheLoader<URI, VAppTemplate> vAppTemplates) {
+ return CacheBuilder.newBuilder().build(vAppTemplates);
+ }
+ @Provides
+ @Singleton
+ protected LoadingCache<URI, Envelope> envelopes(CacheLoader<URI, Envelope> envelopes) {
+ return CacheBuilder.newBuilder().build(envelopes);
+ }
+
@Override
protected void bindErrorHandlers() {
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(ParseVCloudErrorFromHttpResponse.class);
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/VApp.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/VApp.java
index 3efc1a5..2ba7ea4 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/VApp.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/VApp.java
@@ -22,6 +22,7 @@
import java.util.Set;
import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.vcloud.domain.ovf.VCloudNetworkSection;
/**
* A VApp is the result of instantiation of a {@link VAppTemplate}. <h2>note</h2>
@@ -77,4 +78,12 @@
*/
Set<Vm> getChildren();
+ /**
+ * description of the predefined vApp internal networks in this template
+ *
+ * @return null if the vApp is not yet instantiated
+ * @since vcloud api 1.0
+ */
+ @Nullable
+ VCloudNetworkSection getNetworkSection();
}
\ No newline at end of file
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/TaskImpl.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/TaskImpl.java
index a38dd71..828bc29 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/TaskImpl.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/TaskImpl.java
@@ -31,6 +31,8 @@
import org.jclouds.vcloud.domain.TaskStatus;
import org.jclouds.vcloud.domain.VCloudError;
+import com.google.common.base.Objects;
+
/**
*
* @author Adrian Cole
@@ -88,10 +90,9 @@
@Override
public String toString() {
- return "TaskImpl [endTime=" + endTime + ", error=" + error + ", expiryTime=" + expiryTime + ", operation="
- + operation + ", owner=" + owner + ", startTime=" + startTime + ", status=" + status + ", getHref()="
- + getHref() + ", getName()=" + getName() + ", getType()=" + getType() + ", toString()="
- + super.toString() + ", getClass()=" + getClass() + "]";
+ return Objects.toStringHelper("").add("href", getHref()).add("name", getName()).add("owner", owner).add(
+ "operation", operation).add("startTime", startTime).add("endTime", endTime)
+ .add("expiryTime", expiryTime).add("error", error).toString();
}
public Date getExpiryTime() {
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/VAppImpl.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/VAppImpl.java
index f44a763..fc7eb44 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/VAppImpl.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/VAppImpl.java
@@ -31,6 +31,7 @@
import org.jclouds.vcloud.domain.Task;
import org.jclouds.vcloud.domain.VApp;
import org.jclouds.vcloud.domain.Vm;
+import org.jclouds.vcloud.domain.ovf.VCloudNetworkSection;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@@ -51,9 +52,12 @@
private final List<Task> tasks = Lists.newArrayList();
private final boolean ovfDescriptorUploaded;
private final Set<Vm> children = Sets.newLinkedHashSet();
-
+ @Nullable
+ private final VCloudNetworkSection networkSection;
+
public VAppImpl(String name, String type, URI id, Status status, ReferenceType vdc, @Nullable String description,
- Iterable<Task> tasks, boolean ovfDescriptorUploaded, Iterable<Vm> children) {
+ Iterable<Task> tasks, boolean ovfDescriptorUploaded, Iterable<Vm> children,
+ @Nullable VCloudNetworkSection networkSection) {
super(name, type, id);
this.status = checkNotNull(status, "status");
this.vdc = vdc;// TODO: once <1.0 is killed check not null
@@ -61,6 +65,7 @@
Iterables.addAll(this.tasks, checkNotNull(tasks, "tasks"));
this.ovfDescriptorUploaded = ovfDescriptorUploaded;
Iterables.addAll(this.children, checkNotNull(children, "children"));
+ this.networkSection = networkSection; // can be null when copying
}
/**
@@ -110,7 +115,15 @@
public Set<Vm> getChildren() {
return children;
}
-
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public VCloudNetworkSection getNetworkSection() {
+ return networkSection;
+ }
+
@Override
public int hashCode() {
final int prime = 31;
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/network/NetworkConfig.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/network/NetworkConfig.java
index c2fb670..3a5ec8b 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/network/NetworkConfig.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/network/NetworkConfig.java
@@ -23,12 +23,51 @@
import java.net.URI;
import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.ovf.NetworkSection;
/**
*
* @author Adrian Cole
*/
public class NetworkConfig {
+
+ public Builder toBuilder() {
+ return builder().fromNetworkConfig(this);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private String networkName;
+ private URI parentNetwork;
+ private FenceMode fenceMode;
+
+ public Builder networkName(String networkName) {
+ this.networkName = networkName;
+ return this;
+ }
+
+ public Builder parentNetwork(URI parentNetwork) {
+ this.parentNetwork = parentNetwork;
+ return this;
+ }
+
+ public Builder fenceMode(FenceMode fenceMode) {
+ this.fenceMode = fenceMode;
+ return this;
+ }
+
+ public Builder fromNetworkConfig(NetworkConfig in) {
+ return networkName(in.getNetworkName()).parentNetwork(in.getParentNetwork()).fenceMode(in.getFenceMode());
+ }
+
+ public NetworkConfig build() {
+ return new NetworkConfig(networkName, parentNetwork, fenceMode);
+ }
+ }
+
@Nullable
private final String networkName;
private final URI parentNetwork;
@@ -87,7 +126,6 @@
return fenceMode;
}
-
@Override
public int hashCode() {
final int prime = 31;
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInOrg.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInOrg.java
index 1151826..fc48add 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInOrg.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInOrg.java
@@ -18,11 +18,9 @@
*/
package org.jclouds.vcloud.functions;
-import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Singleton;
-import org.jclouds.logging.Logger;
import org.jclouds.vcloud.domain.Catalog;
import org.jclouds.vcloud.domain.CatalogItem;
import org.jclouds.vcloud.domain.Org;
@@ -36,9 +34,6 @@
@Singleton
public class AllCatalogItemsInOrg implements Function<Org, Iterable<CatalogItem>> {
- @Resource
- public Logger logger = Logger.NULL;
-
private final Function<Org, Iterable<Catalog>> allCatalogsInOrg;
private final Function<Catalog, Iterable<CatalogItem>> allCatalogItemsInCatalog;
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/DefaultNetworkNameInTemplate.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/DefaultNetworkNameInTemplate.java
new file mode 100644
index 0000000..4c947e8
--- /dev/null
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/DefaultNetworkNameInTemplate.java
@@ -0,0 +1,49 @@
+/**
+ * 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.vcloud.functions;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.Iterables.get;
+
+import java.util.Set;
+
+import javax.annotation.Resource;
+import javax.inject.Singleton;
+
+import org.jclouds.logging.Logger;
+import org.jclouds.ovf.Network;
+import org.jclouds.vcloud.domain.VAppTemplate;
+
+import com.google.common.base.Function;
+
+@Singleton
+public class DefaultNetworkNameInTemplate implements Function<VAppTemplate, String> {
+ @Resource
+ protected Logger logger = Logger.NULL;
+
+ @Override
+ public String apply(VAppTemplate vAppTemplate) {
+ checkArgument(vAppTemplate != null, "vAppTemplate was null!");
+ Set<Network> networks = vAppTemplate.getNetworkSection().getNetworks();
+ checkArgument(networks.size() > 0, "no networks found in vAppTemplate %s", vAppTemplate);
+ if (networks.size() > 1)
+ logger.warn("multiple networks found for %s, choosing first from: %s", vAppTemplate.getName(), networks);
+ return get(networks, 0).getName();
+ }
+}
\ No newline at end of file
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesInOrg.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesInOrg.java
index f2ea52a..b4b733d 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesInOrg.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesInOrg.java
@@ -18,20 +18,21 @@
*/
package org.jclouds.vcloud.functions;
-import java.util.Map;
+import static com.google.common.base.Predicates.and;
+import static com.google.common.base.Predicates.notNull;
+import static com.google.common.collect.Iterables.filter;
import javax.inject.Inject;
import javax.inject.Singleton;
-import org.jclouds.domain.Credentials;
import org.jclouds.vcloud.domain.CatalogItem;
import org.jclouds.vcloud.domain.Org;
+import org.jclouds.vcloud.domain.Status;
import org.jclouds.vcloud.domain.VAppTemplate;
-import org.jclouds.vcloud.functions.AllCatalogItemsInOrg;
import com.google.common.base.Function;
-import com.google.common.base.Predicates;
-import com.google.common.collect.Iterables;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableSet;
/**
* @author Adrian Cole
@@ -39,13 +40,12 @@
@Singleton
public class VAppTemplatesInOrg implements Function<Org, Iterable<VAppTemplate>> {
- private final AllCatalogItemsInOrg allCatalogItemsInOrg;
+ private final Function<Org, Iterable<CatalogItem>> allCatalogItemsInOrg;
private final Function<Iterable<CatalogItem>, Iterable<VAppTemplate>> vAppTemplatesForCatalogItems;
@Inject
- VAppTemplatesInOrg(AllCatalogItemsInOrg allCatalogItemsInOrg,
- Function<Iterable<CatalogItem>, Iterable<VAppTemplate>> vAppTemplatesForCatalogItems,
- Map<String, Credentials> credentialStore) {
+ VAppTemplatesInOrg(Function<Org, Iterable<CatalogItem>> allCatalogItemsInOrg,
+ Function<Iterable<CatalogItem>, Iterable<VAppTemplate>> vAppTemplatesForCatalogItems) {
this.allCatalogItemsInOrg = allCatalogItemsInOrg;
this.vAppTemplatesForCatalogItems = vAppTemplatesForCatalogItems;
}
@@ -54,7 +54,17 @@
public Iterable<VAppTemplate> apply(Org from) {
Iterable<CatalogItem> catalogs = allCatalogItemsInOrg.apply(from);
Iterable<VAppTemplate> vAppTemplates = vAppTemplatesForCatalogItems.apply(catalogs);
- return Iterables.filter(vAppTemplates, Predicates.notNull());
+ return filter(vAppTemplates, and(notNull(), new Predicate<VAppTemplate>(){
+
+ //TODO: test this
+ @Override
+ public boolean apply(VAppTemplate input) {
+ if (input == null)
+ return false;
+ return ImmutableSet.of(Status.RESOLVED, Status.OFF).contains(input.getStatus());
+ }
+
+ }));
}
}
\ No newline at end of file
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/handlers/ParseVCloudErrorFromHttpResponse.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/handlers/ParseVCloudErrorFromHttpResponse.java
index 9bc2f16..d67e911 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/handlers/ParseVCloudErrorFromHttpResponse.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/handlers/ParseVCloudErrorFromHttpResponse.java
@@ -37,7 +37,6 @@
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.util.Strings2;
-import org.jclouds.vcloud.VCloudMediaType;
import org.jclouds.vcloud.VCloudResponseException;
import org.jclouds.vcloud.domain.VCloudError;
import org.jclouds.vcloud.domain.VCloudError.MinorCode;
@@ -68,19 +67,18 @@
VCloudError error = null;
String message = null;
if (response.getPayload() != null) {
- String contentType = response.getPayload().getContentMetadata().getContentType();
- if (VCloudMediaType.ERROR_XML.equals(contentType)) {
+ try {
error = utils.parseErrorFromContent(request, response);
if (error != null) {
message = error.getMessage();
exception = new VCloudResponseException(command, response, error);
- }
- } else {
- try {
+ } else {
message = Strings2.toStringAndClose(response.getPayload().getInput());
exception = message != null ? new HttpResponseException(command, response, message) : exception;
- } catch (IOException e) {
}
+ } catch (IOException e) {
+ } finally {
+ response.getPayload().release();
}
}
message = message != null ? message : String.format("%s -> %s", request.getRequestLine(), response
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/loaders/OVFLoader.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/loaders/OVFLoader.java
new file mode 100644
index 0000000..719d35d
--- /dev/null
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/loaders/OVFLoader.java
@@ -0,0 +1,49 @@
+/**
+ * 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.vcloud.loaders;
+
+import java.net.URI;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.logging.Logger;
+import org.jclouds.ovf.Envelope;
+import org.jclouds.vcloud.VCloudClient;
+
+import com.google.common.cache.CacheLoader;
+
+@Singleton
+public class OVFLoader extends CacheLoader<URI, Envelope> {
+ @Resource
+ protected Logger logger = Logger.NULL;
+
+ private final VCloudClient client;
+
+ @Inject
+ OVFLoader(VCloudClient client) {
+ this.client = client;
+ }
+
+ @Override
+ public Envelope load(URI template) {
+ return client.getVAppTemplateClient().getOvfEnvelopeForVAppTemplate(template);
+ }
+}
\ No newline at end of file
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/loaders/VAppTemplateLoader.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/loaders/VAppTemplateLoader.java
new file mode 100644
index 0000000..3189faf
--- /dev/null
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/loaders/VAppTemplateLoader.java
@@ -0,0 +1,49 @@
+/**
+ * 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.vcloud.loaders;
+
+import java.net.URI;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.logging.Logger;
+import org.jclouds.vcloud.VCloudClient;
+import org.jclouds.vcloud.domain.VAppTemplate;
+
+import com.google.common.cache.CacheLoader;
+
+@Singleton
+public class VAppTemplateLoader extends CacheLoader<URI, VAppTemplate> {
+ @Resource
+ protected Logger logger = Logger.NULL;
+
+ private final VCloudClient client;
+
+ @Inject
+ VAppTemplateLoader(VCloudClient client) {
+ this.client = client;
+ }
+
+ @Override
+ public VAppTemplate load(URI template) {
+ return client.getVAppTemplateClient().getVAppTemplate(template);
+ }
+}
\ No newline at end of file
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptions.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptions.java
index 3be4d56..de7f985 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptions.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptions.java
@@ -36,18 +36,13 @@
private Boolean customizeOnInstantiate;
private String description = null;
- private boolean block = true;
private boolean deploy = true;
private boolean powerOn = true;
public String getDescription() {
return description;
}
-
- public boolean shouldBlock() {
- return block;
- }
-
+
public boolean shouldDeploy() {
return deploy;
}
@@ -80,24 +75,7 @@
this.powerOn = powerOn;
return this;
}
-
- /**
- * block until instantiate or deployment operations complete?
- */
- public InstantiateVAppTemplateOptions block(boolean block) {
- this.block = block;
- return this;
- }
-
- /**
- * If true, then customization is executed for all children that include a
- * GuestCustomizationSection.
- */
- public InstantiateVAppTemplateOptions customizeOnInstantiate(boolean customizeOnInstantiate) {
- this.customizeOnInstantiate = customizeOnInstantiate;
- return this;
- }
-
+
/**
* {@networkConfig VAppTemplate}s have internal networks that can be
* connected in order to access the internet or other external networks.
@@ -123,21 +101,9 @@
return networkConfig;
}
- public Boolean shouldCustomizeOnInstantiate() {
- return customizeOnInstantiate;
- }
-
public static class Builder {
/**
- * @see InstantiateVAppTemplateOptions#block
- */
- public static InstantiateVAppTemplateOptions block(boolean block) {
- InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions();
- return options.block(block);
- }
-
- /**
* @see InstantiateVAppTemplateOptions#description
*/
public static InstantiateVAppTemplateOptions description(String description) {
@@ -162,14 +128,6 @@
}
/**
- * @see InstantiateVAppTemplateOptions#customizeOnInstantiate
- */
- public static InstantiateVAppTemplateOptions customizeOnInstantiate(Boolean customizeOnInstantiate) {
- InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions();
- return options.customizeOnInstantiate(customizeOnInstantiate);
- }
-
- /**
* @see InstantiateVAppTemplateOptions#addNetworkConfig
*/
public static InstantiateVAppTemplateOptions addNetworkConfig(NetworkConfig networkConfig) {
@@ -182,14 +140,13 @@
@Override
public String toString() {
return "[networkConfig=" + networkConfig + ", customizeOnInstantiate=" + customizeOnInstantiate
- + ", description=" + description + ", block=" + block + ", deploy=" + deploy + ", powerOn=" + powerOn + "]";
+ + ", description=" + description + ", deploy=" + deploy + ", powerOn=" + powerOn + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
- result = prime * result + (block ? 1231 : 1237);
result = prime * result + ((customizeOnInstantiate == null) ? 0 : customizeOnInstantiate.hashCode());
result = prime * result + (deploy ? 1231 : 1237);
result = prime * result + ((description == null) ? 0 : description.hashCode());
@@ -207,8 +164,6 @@
if (getClass() != obj.getClass())
return false;
InstantiateVAppTemplateOptions other = (InstantiateVAppTemplateOptions) obj;
- if (block != other.block)
- return false;
if (customizeOnInstantiate == null) {
if (other.customizeOnInstantiate != null)
return false;
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/predicates/TaskSuccess.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/predicates/TaskSuccess.java
index 0425629..00f3346 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/predicates/TaskSuccess.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/predicates/TaskSuccess.java
@@ -24,6 +24,7 @@
import javax.inject.Singleton;
import org.jclouds.logging.Logger;
+import org.jclouds.vcloud.TaskInErrorStateException;
import org.jclouds.vcloud.VCloudClient;
import org.jclouds.vcloud.domain.Task;
import org.jclouds.vcloud.domain.TaskStatus;
@@ -59,7 +60,7 @@
return false;
logger.trace("%s: looking for status %s: currently: %s", task, TaskStatus.SUCCESS, task.getStatus());
if (task.getStatus() == TaskStatus.ERROR)
- throw new RuntimeException("error on task: " + task.getHref() + " error: " + task.getError());
+ throw new TaskInErrorStateException(task);
return task.getStatus() == TaskStatus.SUCCESS;
}
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/util/VCloudUtils.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/util/VCloudUtils.java
index 54b6db6..4386e2a 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/util/VCloudUtils.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/util/VCloudUtils.java
@@ -54,7 +54,10 @@
// HEAD has no content
if (response.getPayload() == null)
return null;
- if (VCloudMediaType.ERROR_XML.equals(response.getPayload().getContentMetadata().getContentType())) {
+ // NOTE in vCloud Datacenter 1.5, if you make vCloud 1.0 requests, the content type
+ // header is suffixed with ;1.0
+ String contentType = response.getPayload().getContentMetadata().getContentType();
+ if (contentType != null && contentType.startsWith(VCloudMediaType.ERROR_XML)) {
try {
return (VCloudError) factory.create(errorHandlerProvider.get()).setContext(request).apply(response);
} catch (RuntimeException e) {
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppHandler.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppHandler.java
index 5cfeb16..a39e2d4 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppHandler.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppHandler.java
@@ -35,6 +35,8 @@
import org.jclouds.vcloud.domain.VApp;
import org.jclouds.vcloud.domain.Vm;
import org.jclouds.vcloud.domain.internal.VAppImpl;
+import org.jclouds.vcloud.domain.ovf.VCloudNetworkSection;
+import org.jclouds.vcloud.xml.ovf.VCloudNetworkSectionHandler;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
@@ -48,11 +50,14 @@
protected final TaskHandler taskHandler;
protected final VmHandler vmHandler;
+ protected final VCloudNetworkSectionHandler networkSectionHandler;
@Inject
- public VAppHandler(TaskHandler taskHandler, VmHandler vmHandler) {
+ public VAppHandler(TaskHandler taskHandler, VmHandler vmHandler,
+ VCloudNetworkSectionHandler networkSectionHandler) {
this.taskHandler = taskHandler;
this.vmHandler = vmHandler;
+ this.networkSectionHandler = networkSectionHandler;
}
protected StringBuilder currentText = new StringBuilder();
@@ -66,11 +71,13 @@
private boolean inChildren;
private boolean inTasks;
+ private boolean inNetworkSection;
protected Set<Vm> children = Sets.newLinkedHashSet();
+ private VCloudNetworkSection networkSection;
public VApp getResult() {
return new VAppImpl(template.getName(), template.getType(), template.getHref(), status, vdc, description, tasks,
- ovfDescriptorUploaded, children);
+ ovfDescriptorUploaded, children, networkSection);
}
protected int depth = 0;
@@ -84,12 +91,16 @@
inChildren = true;
} else if (equalsOrSuffix(qName, "Tasks")) {
inTasks = true;
+ } else if (equalsOrSuffix(qName, "NetworkSection")) {
+ inNetworkSection = true;
}
}
if (inChildren) {
vmHandler.startElement(uri, localName, qName, attrs);
} else if (inTasks) {
taskHandler.startElement(uri, localName, qName, attrs);
+ } else if (inNetworkSection) {
+ networkSectionHandler.startElement(uri, localName, qName, attrs);
} else if (equalsOrSuffix(qName, "VApp")) {
template = newReferenceType(attributes);
if (attributes.containsKey("status"))
@@ -111,12 +122,17 @@
this.tasks.add(taskHandler.getResult());
} else if (equalsOrSuffix(qName, "Description")) {
description = SaxUtils.currentOrNull(currentText);
+ } else if (equalsOrSuffix(qName, "NetworkSection")) {
+ inNetworkSection = false;
+ this.networkSection = networkSectionHandler.getResult();
}
}
if (inChildren) {
vmHandler.endElement(uri, name, qName);
} else if (inTasks) {
taskHandler.endElement(uri, name, qName);
+ } else if (inNetworkSection) {
+ networkSectionHandler.endElement(uri, name, qName);
} else if (equalsOrSuffix(qName, "ovfDescriptorUploaded")) {
ovfDescriptorUploaded = Boolean.parseBoolean(SaxUtils.currentOrNull(currentText));
}
@@ -124,11 +140,14 @@
}
public void characters(char ch[], int start, int length) {
- currentText.append(ch, start, length);
if (inTasks)
taskHandler.characters(ch, start, length);
- if (inChildren)
+ else if (inChildren)
vmHandler.characters(ch, start, length);
+ else if (inNetworkSection)
+ networkSectionHandler.characters(ch, start, length);
+ else
+ currentText.append(ch, start, length);
}
}
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppTemplateHandler.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppTemplateHandler.java
index 8a49e14..43d66a8 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppTemplateHandler.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppTemplateHandler.java
@@ -18,6 +18,7 @@
*/
package org.jclouds.vcloud.xml;
+import static org.jclouds.util.SaxUtils.equalsOrSuffix;
import static org.jclouds.vcloud.util.Utils.newReferenceType;
import java.util.List;
@@ -83,11 +84,11 @@
@Override
public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
Map<String, String> attributes = SaxUtils.cleanseAttributes(attrs);
- if (qName.endsWith("Children")) {
+ if (equalsOrSuffix(qName, "Children")) {
inChildren = true;
- } else if (qName.endsWith("Tasks")) {
+ } else if (equalsOrSuffix(qName, "Tasks")) {
inTasks = true;
- } else if (qName.endsWith("NetworkSection")) {
+ } else if (equalsOrSuffix(qName, "NetworkSection")) {
inNetworkSection = true;
}
if (inChildren) {
@@ -96,26 +97,26 @@
taskHandler.startElement(uri, localName, qName, attrs);
} else if (inNetworkSection) {
networkSectionHandler.startElement(uri, localName, qName, attrs);
- } else if (qName.equals("VAppTemplate")) {
+ } else if (equalsOrSuffix(qName, "VAppTemplate")) {
template = newReferenceType(attributes);
if (attributes.containsKey("status"))
this.status = Status.fromValue(Integer.parseInt(attributes.get("status")));
- } else if (qName.equals("Link") && "up".equals(attributes.get("rel"))) {
+ } else if (equalsOrSuffix(qName, "Link") && "up".equals(attributes.get("rel"))) {
vdc = newReferenceType(attributes);
}
}
public void endElement(String uri, String name, String qName) {
- if (qName.endsWith("Children")) {
+ if (equalsOrSuffix(qName, "Children")) {
inChildren = false;
Vm vm = vmHandler.getResult();
if (vm != null)
this.children.add(vmHandler.getResult());
- } else if (qName.endsWith("Tasks")) {
+ } else if (equalsOrSuffix(qName, "Tasks")) {
inTasks = false;
this.tasks.add(taskHandler.getResult());
- } else if (qName.endsWith("NetworkSection")) {
+ } else if (equalsOrSuffix(qName, "NetworkSection")) {
inNetworkSection = false;
this.networkSection = networkSectionHandler.getResult();
}
@@ -125,11 +126,11 @@
taskHandler.endElement(uri, name, qName);
} else if (inNetworkSection) {
networkSectionHandler.endElement(uri, name, qName);
- } else if (qName.equals("Description")) {
+ } else if (equalsOrSuffix(qName, "Description")) {
description = currentOrNull();
- } else if (qName.equals("VAppScopedLocalId")) {
+ } else if (equalsOrSuffix(qName, "VAppScopedLocalId")) {
vAppScopedLocalId = currentOrNull();
- } else if (qName.equals("ovfDescriptorUploaded")) {
+ } else if (equalsOrSuffix(qName, "ovfDescriptorUploaded")) {
ovfDescriptorUploaded = Boolean.parseBoolean(currentOrNull());
}
currentText = new StringBuilder();
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/ovf/VCloudNetworkSectionHandler.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/ovf/VCloudNetworkSectionHandler.java
index b6ccdb8..f1a716b 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/ovf/VCloudNetworkSectionHandler.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/ovf/VCloudNetworkSectionHandler.java
@@ -18,6 +18,8 @@
*/
package org.jclouds.vcloud.xml.ovf;
+import static org.jclouds.util.SaxUtils.equalsOrSuffix;
+
import java.util.Map;
import javax.inject.Inject;
@@ -51,7 +53,7 @@
public void startElement(String uri, String localName, String qName, Attributes attrs) {
Map<String, String> attributes = SaxUtils.cleanseAttributes(attrs);
- if (qName.endsWith("NetworkSection")) {
+ if (equalsOrSuffix(qName, "NetworkSection")) {
this.net = Utils.newReferenceType(attributes);
}
networkSectionHandler.startElement(uri, localName, qName, attrs);
diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayloadTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayloadTest.java
index c6dad9b..d77d684 100644
--- a/apis/vcloud/src/test/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayloadTest.java
+++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayloadTest.java
@@ -19,37 +19,40 @@
package org.jclouds.vcloud.binders;
import static com.google.common.base.Preconditions.checkNotNull;
+import static org.easymock.EasyMock.createMock;
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.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.addNetworkConfig;
-import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.customizeOnInstantiate;
+import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_FENCEMODE;
import java.io.IOException;
import java.net.URI;
import java.util.Map;
import java.util.Properties;
+import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.util.Strings2;
-import org.jclouds.vcloud.VCloudClient;
import org.jclouds.vcloud.VCloudPropertiesBuilder;
import org.jclouds.vcloud.domain.ReferenceType;
import org.jclouds.vcloud.domain.VAppTemplate;
import org.jclouds.vcloud.domain.internal.ReferenceTypeImpl;
import org.jclouds.vcloud.domain.network.FenceMode;
import org.jclouds.vcloud.domain.network.NetworkConfig;
-import org.jclouds.vcloud.domain.ovf.VCloudNetworkSection;
import org.jclouds.vcloud.endpoints.Network;
-import org.jclouds.vcloud.features.VAppTemplateClient;
import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions;
import org.testng.annotations.Test;
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
@@ -64,22 +67,37 @@
*/
@Test(groups = "unit")
public class BindInstantiateVAppTemplateParamsToXmlPayloadTest {
- Injector createInjector(URI vAppTemplate, VAppTemplate value) {
- final VCloudClient client = createMock(VCloudClient.class);
- final VAppTemplateClient tclient = createMock(VAppTemplateClient.class);
-
- expect(client.getVAppTemplateClient()).andReturn(tclient).anyTimes();
- expect(tclient.getVAppTemplate(vAppTemplate)).andReturn(value).anyTimes();
- replay(client);
- replay(tclient);
+ Injector createInjector(final URI vAppTemplate, final VAppTemplate value) {
return Guice.createInjector(new AbstractModule() {
+ @SuppressWarnings("unused")
+ @Provides
+ @Singleton
+ @Network
+ protected Function<VAppTemplate, String> templateToDefaultNetworkName() {
+ return Functions.forMap(ImmutableMap.of(value, "vAppNet-vApp Internal"));
+ }
+
+ @SuppressWarnings("unused")
+ @Provides
+ @Singleton
+ protected LoadingCache<URI, VAppTemplate> templateIdToVAppTemplate() {
+ return CacheBuilder.newBuilder().build(
+ CacheLoader.from(Functions.forMap(ImmutableMap.of(vAppTemplate, value))));
+ }
+
@Override
protected void configure() {
Properties props = new Properties();
Names.bindProperties(binder(), checkNotNull(new VCloudPropertiesBuilder(props).build(), "properties"));
- bind(VCloudClient.class).toInstance(client);
+ }
+
+ @SuppressWarnings("unused")
+ @Provides
+ @Singleton
+ public FenceMode defaultFenceMode(@Named(PROPERTY_VCLOUD_DEFAULT_FENCEMODE) String fenceMode) {
+ return FenceMode.fromValue(fenceMode);
}
@SuppressWarnings("unused")
@@ -87,7 +105,8 @@
@Provides
@Singleton
ReferenceType provideNetwork() {
- return new ReferenceTypeImpl(null, null, URI.create("https://vcenterprise.bluelock.com/api/v1.0/network/1990"));
+ return new ReferenceTypeImpl(null, null, URI
+ .create("https://vcenterprise.bluelock.com/api/v1.0/network/1990"));
}
});
}
@@ -95,91 +114,72 @@
public void testDefault() throws IOException {
URI templateUri = URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3");
VAppTemplate template = createMock(VAppTemplate.class);
- VCloudNetworkSection net = createMock(VCloudNetworkSection.class);
String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/instantiationparams.xml"));
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
expect(request.getArgs()).andReturn(ImmutableList.<Object> of(new InstantiateVAppTemplateOptions()))
- .atLeastOnce();
+ .atLeastOnce();
request.setPayload(expected);
- expect(template.getNetworkSection()).andReturn(net).atLeastOnce();
- expect(net.getNetworks()).andReturn(
- ImmutableSet.<org.jclouds.ovf.Network> of(new org.jclouds.ovf.Network("vAppNet-vApp Internal", null)));
-
- replay(request);
- replay(template);
- replay(net);
+ replay(request, template);
BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance(
- BindInstantiateVAppTemplateParamsToXmlPayload.class);
+ BindInstantiateVAppTemplateParamsToXmlPayload.class);
Map<String, String> map = Maps.newHashMap();
map.put("name", "my-vapp");
map.put("template", templateUri.toASCIIString());
binder.bindToRequest(request, map);
- verify(request);
- verify(template);
- verify(net);
-
+ verify(request, template);
}
public void testDescription() throws IOException {
URI templateUri = URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3");
VAppTemplate template = createMock(VAppTemplate.class);
- VCloudNetworkSection net = createMock(VCloudNetworkSection.class);
- String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/instantiationparams-description.xml"));
+ String expected = Strings2.toStringAndClose(getClass()
+ .getResourceAsStream("/instantiationparams-description.xml"));
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
expect(request.getArgs()).andReturn(
- ImmutableList.<Object> of(new InstantiateVAppTemplateOptions().description("my foo"))).atLeastOnce();
+ ImmutableList.<Object> of(new InstantiateVAppTemplateOptions().description("my foo"))).atLeastOnce();
request.setPayload(expected);
- expect(template.getNetworkSection()).andReturn(net).atLeastOnce();
- expect(net.getNetworks()).andReturn(
- ImmutableSet.<org.jclouds.ovf.Network> of(new org.jclouds.ovf.Network("vAppNet-vApp Internal", null)));
-
- replay(request);
- replay(template);
- replay(net);
+ replay(request, template);
BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance(
- BindInstantiateVAppTemplateParamsToXmlPayload.class);
+ BindInstantiateVAppTemplateParamsToXmlPayload.class);
Map<String, String> map = Maps.newHashMap();
map.put("name", "my-vapp");
map.put("template", templateUri.toASCIIString());
binder.bindToRequest(request, map);
- verify(request);
- verify(template);
- verify(net);
+ verify(request, template);
}
- @Test(expectedExceptions = IllegalArgumentException.class)
public void testWhenTemplateDoesntExist() throws IOException {
URI templateUri = URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3");
- VAppTemplate template = null;
+ VAppTemplate template = createMock(VAppTemplate.class);
String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/instantiationparams.xml"));
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
expect(request.getArgs()).andReturn(ImmutableList.<Object> of()).atLeastOnce();
request.setPayload(expected);
- replay(request);
+ replay(request, template);
BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance(
- BindInstantiateVAppTemplateParamsToXmlPayload.class);
+ BindInstantiateVAppTemplateParamsToXmlPayload.class);
Map<String, String> map = Maps.newHashMap();
map.put("name", "my-vapp");
map.put("template", templateUri.toASCIIString());
binder.bindToRequest(request, map);
- verify(request);
+ verify(request, template);
}
@@ -199,7 +199,7 @@
replay(request);
BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance(
- BindInstantiateVAppTemplateParamsToXmlPayload.class);
+ BindInstantiateVAppTemplateParamsToXmlPayload.class);
Map<String, String> map = Maps.newHashMap();
map.put("name", "my-vapp");
@@ -212,10 +212,10 @@
public void testWithNetworkNameFenceMode() throws IOException {
URI templateUri = URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3");
- VAppTemplate template = null;
+ VAppTemplate template = createMock(VAppTemplate.class);
- InstantiateVAppTemplateOptions options = addNetworkConfig(new NetworkConfig("aloha",
- URI.create("https://vcenterprise.bluelock.com/api/v1.0/network/1991"), FenceMode.NAT_ROUTED));
+ InstantiateVAppTemplateOptions options = addNetworkConfig(new NetworkConfig("aloha", URI
+ .create("https://vcenterprise.bluelock.com/api/v1.0/network/1991"), FenceMode.NAT_ROUTED));
String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/instantiationparams-network.xml"));
@@ -223,54 +223,16 @@
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
expect(request.getArgs()).andReturn(ImmutableList.<Object> of(options)).atLeastOnce();
request.setPayload(expected);
- replay(request);
+ replay(request, template);
BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance(
- BindInstantiateVAppTemplateParamsToXmlPayload.class);
+ BindInstantiateVAppTemplateParamsToXmlPayload.class);
Map<String, String> map = Maps.newHashMap();
map.put("name", "my-vapp");
map.put("template", "https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3");
binder.bindToRequest(request, map);
- verify(request);
- }
-
- public void testWithCustomization() throws IOException {
-
- URI templateUri = URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3");
- VAppTemplate template = createMock(VAppTemplate.class);
- VCloudNetworkSection net = createMock(VCloudNetworkSection.class);
- InstantiateVAppTemplateOptions options = customizeOnInstantiate(true);
-
- String expected = Strings2.toStringAndClose(getClass().getResourceAsStream(
- "/instantiationparams-customization.xml"));
-
- GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
- expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
- expect(request.getArgs()).andReturn(ImmutableList.<Object> of(options)).atLeastOnce();
- request.setPayload(expected);
-
- expect(template.getNetworkSection()).andReturn(net).atLeastOnce();
- expect(net.getNetworks()).andReturn(
- ImmutableSet.<org.jclouds.ovf.Network> of(new org.jclouds.ovf.Network("vAppNet-vApp Internal", null)));
-
- replay(request);
- replay(template);
- replay(net);
-
- BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance(
- BindInstantiateVAppTemplateParamsToXmlPayload.class);
-
- Map<String, String> map = Maps.newHashMap();
- map.put("name", "my-vapp");
- map.put("template", "https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3");
-
- binder.bindToRequest(request, map);
-
- verify(request);
- verify(template);
- verify(net);
-
+ verify(request, template);
}
}
diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/BaseVCloudComputeServiceExpectTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/BaseVCloudComputeServiceExpectTest.java
new file mode 100644
index 0000000..833e9ba
--- /dev/null
+++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/BaseVCloudComputeServiceExpectTest.java
@@ -0,0 +1,161 @@
+/**
+ * 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.vcloud.compute;
+
+import java.net.URI;
+import java.util.Properties;
+
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.ComputeServiceContextFactory;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.logging.config.NullLoggingModule;
+import org.jclouds.rest.BaseRestClientExpectTest;
+import org.jclouds.vcloud.VCloudMediaType;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.net.HttpHeaders;
+import com.google.inject.Module;
+
+/**
+ * Base class for writing VCloud Expect tests for ComputeService operations
+ *
+ * @author Adrian Cole
+ */
+public abstract class BaseVCloudComputeServiceExpectTest extends BaseRestClientExpectTest<ComputeService> {
+ protected static final String ENDPOINT = "https://zone.myvcloud.com/api";
+
+ protected HttpRequest versionsRequest = HttpRequest.builder().method("GET").endpoint(
+ URI.create(ENDPOINT + "/versions")).build();
+
+ protected HttpResponse versionsResponseFromVCD1_5 = HttpResponse.builder().statusCode(200)
+ .message("HTTP/1.1 200 OK").payload(payloadFromResourceWithContentType("/versions-vcd15.xml", "text/xml"))
+ .build();
+
+ // initial auth is using basic
+ protected HttpRequest version1_0LoginRequest = HttpRequest.builder().method("POST").endpoint(
+ URI.create(ENDPOINT + "/v1.0/login"))
+ .headers(ImmutableMultimap.<String, String> builder()
+ .put(HttpHeaders.ACCEPT, VCloudMediaType.ORGLIST_XML)
+ .put(HttpHeaders.AUTHORIZATION, "Basic dXNlckBvcmc6cGFzc3dvcmQ=").build()).build();
+
+ protected String sessionToken = "AtatAgvJMrwOc9pDQq4RRCRLazThpnTKJDxSVH9oB2I=";
+
+ // login response includes a cookie and also a vcloud extended header with the session token in it
+ // NOTE: vCloud Director 1.5 returns ;version=1.0 on responses to requests made in 1.0 format.
+ protected HttpResponse successfulVersion1_0LoginResponseFromVCD1_5WithSingleOrg = HttpResponse.builder().statusCode(200)
+ .message("HTTP/1.1 200 OK").payload(payloadFromResourceWithContentType("/orgList1.0-vcd15.xml", VCloudMediaType.ORGLIST_XML +";version=1.0"))
+ .headers(ImmutableMultimap.<String, String> builder()
+ .put("x-vcloud-authorization", sessionToken)
+ .put(HttpHeaders.SET_COOKIE, String.format("vcloud-token=%s; Secure; Path=/", sessionToken)).build()).build();
+
+ // objects are looked up by id and the format of the id is hex-hyphen
+ protected String orgId = "c076f90a-397a-49fa-89b8-b294c1599cd0";
+
+ protected HttpRequest version1_0GetOrgRequest = HttpRequest.builder().method("GET").endpoint(
+ URI.create(ENDPOINT + "/v1.0/org/" + orgId))
+ .headers(ImmutableMultimap.<String, String> builder()
+ .put(HttpHeaders.ACCEPT, VCloudMediaType.ORG_XML)
+ .put(HttpHeaders.COOKIE, "vcloud-token=" + sessionToken).build()).build();
+
+ protected HttpResponse successfulVersion1_0GetOrgResponseFromVCD1_5WithSingleTasksListVDCAndNetwork = HttpResponse.builder().statusCode(200)
+ .message("HTTP/1.1 200 OK").payload(payloadFromResourceWithContentType("/org1.0-vcd15.xml", VCloudMediaType.ORG_XML +";version=1.0"))
+ .build();
+
+ protected String catalogId = "3155f393-1e1d-4572-8c9c-d76f72ddb658";
+ protected String vdcId = "e9cd3387-ac57-4d27-a481-9bee75e0690f";
+
+ protected HttpRequest version1_0GetCatalogRequest = HttpRequest.builder().method("GET").endpoint(
+ URI.create(ENDPOINT + "/v1.0/catalog/" + catalogId))
+ .headers(ImmutableMultimap.<String, String> builder()
+ .put(HttpHeaders.ACCEPT, VCloudMediaType.CATALOG_XML)
+ .put(HttpHeaders.COOKIE, "vcloud-token=" + sessionToken).build()).build();
+
+ protected HttpResponse successfulVersion1_0GetCatalogResponseFromVCD1_5WithSingleTemplate = HttpResponse.builder().statusCode(200)
+ .message("HTTP/1.1 200 OK").payload(payloadFromResourceWithContentType("/catalog1.0-vcd15.xml", VCloudMediaType.CATALOG_XML +";version=1.0"))
+ .build();
+
+ protected String catalogItemId = "ceb369f7-1d07-4e32-9dbd-ebb5aa6ca55c";
+
+ protected HttpRequest version1_0GetCatalogItemRequest = HttpRequest.builder().method("GET").endpoint(
+ URI.create(ENDPOINT + "/v1.0/catalogItem/" + catalogItemId))
+ .headers(ImmutableMultimap.<String, String> builder()
+ .put(HttpHeaders.ACCEPT, VCloudMediaType.CATALOGITEM_XML)
+ .put(HttpHeaders.COOKIE, "vcloud-token=" + sessionToken).build()).build();
+
+ protected HttpResponse successfulVersion1_0GetCatalogItemResponseFromVCD1_5ForTemplate = HttpResponse.builder().statusCode(200)
+ .message("HTTP/1.1 200 OK").payload(payloadFromResourceWithContentType("/catalogItem1.0-vcd15.xml", VCloudMediaType.CATALOGITEM_XML +";version=1.0"))
+ .build();
+
+ // note vAppTemplate has a prefix in its id
+ protected String templateId = "vappTemplate-51891b97-c5dd-47dc-a687-aabae354f728";
+
+ protected HttpRequest version1_0GetVDCRequest = HttpRequest.builder().method("GET").endpoint(
+ URI.create(ENDPOINT + "/v1.0/vdc/" + vdcId))
+ .headers(ImmutableMultimap.<String, String> builder()
+ .put(HttpHeaders.ACCEPT, VCloudMediaType.VDC_XML)
+ .put(HttpHeaders.COOKIE, "vcloud-token=" + sessionToken).build()).build();
+
+ protected HttpResponse successfulVersion1_0GetVDCResponseFromVCD1_5WithSingleTemplateAndNetwork = HttpResponse.builder().statusCode(200)
+ .message("HTTP/1.1 200 OK").payload(payloadFromResourceWithContentType("/vdc1.0-vcd15.xml", VCloudMediaType.VDC_XML +";version=1.0"))
+ .build();
+
+ protected String networkId = "b466c0c5-8a5c-4335-b703-a2e2e6b5f3e1";
+
+ protected HttpRequest version1_0GetVAppTemplateRequest = HttpRequest.builder().method("GET").endpoint(
+ URI.create(ENDPOINT + "/v1.0/vAppTemplate/" + templateId))
+ .headers(ImmutableMultimap.<String, String> builder()
+ .put(HttpHeaders.ACCEPT, VCloudMediaType.VAPPTEMPLATE_XML)
+ .put(HttpHeaders.COOKIE, "vcloud-token=" + sessionToken).build()).build();
+
+ protected HttpResponse successfulVersion1_0GetVAppTemplateResponseFromVCD1_5WithSingleVMAndVDCParent = HttpResponse.builder().statusCode(200)
+ .message("HTTP/1.1 200 OK").payload(payloadFromResourceWithContentType("/template1.0-vcd15.xml", VCloudMediaType.VAPPTEMPLATE_XML +";version=1.0"))
+ .build();
+
+ protected HttpRequest version1_0GetOVFForVAppTemplateRequest = HttpRequest.builder().method("GET").endpoint(
+ URI.create(ENDPOINT + "/v1.0/vAppTemplate/" + templateId + "/ovf"))
+ .headers(ImmutableMultimap.<String, String> builder()
+ .put(HttpHeaders.ACCEPT, MediaType.TEXT_XML)
+ .put(HttpHeaders.COOKIE, "vcloud-token=" + sessionToken).build()).build();
+
+ protected HttpResponse successfulVersion1_0GetOVFForVAppTemplateResponseFromVCD1_5WithSingleVM = HttpResponse.builder().statusCode(200)
+ .message("HTTP/1.1 200 OK").payload(payloadFromResourceWithContentType("/ovf-ubuntu64.xml", MediaType.TEXT_XML +";version=1.0"))
+ .build();
+
+ public BaseVCloudComputeServiceExpectTest() {
+ provider = "vcloud";
+ }
+
+ @Override
+ public ComputeService createClient(Function<HttpRequest, HttpResponse> fn, Module module, Properties props) {
+ return new ComputeServiceContextFactory(setupRestProperties())
+ .createContext(provider, "user@org", "password", ImmutableSet.<Module> of(new ExpectModule(fn),
+ new NullLoggingModule(), module), props).getComputeService();
+ }
+ @Override
+ protected Properties setupProperties() {
+ Properties props = super.setupProperties();
+ props.setProperty(provider+".endpoint", ENDPOINT);
+ return props;
+ }
+}
diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/VCloudComputeServiceLiveTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/VCloudComputeServiceLiveTest.java
index 2d5ec8a..aa6185c 100644
--- a/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/VCloudComputeServiceLiveTest.java
+++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/VCloudComputeServiceLiveTest.java
@@ -18,22 +18,12 @@
*/
package org.jclouds.vcloud.compute;
-import static org.testng.Assert.assertEquals;
-
import org.jclouds.compute.BaseComputeServiceLiveTest;
-import org.jclouds.compute.ComputeServiceContextFactory;
-import org.jclouds.compute.domain.ComputeMetadata;
-import org.jclouds.compute.domain.ComputeType;
import org.jclouds.compute.domain.NodeMetadata;
-import org.jclouds.rest.RestContext;
import org.jclouds.sshj.config.SshjSshClientModule;
-import org.jclouds.vcloud.VCloudAsyncClient;
-import org.jclouds.vcloud.VCloudClient;
-import org.jclouds.vcloud.domain.VApp;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
import com.google.inject.Module;
/**
@@ -46,47 +36,30 @@
public VCloudComputeServiceLiveTest() {
provider = "vcloud";
- // vcloud requires instantiate before deploy, which takes longer than 30 seconds
- nonBlockDurationSeconds = 300;
+ }
+
+ @Override
+ public void setServiceDefaults() {
+ // extremely short names needed so that we don't get errors relating to
+ // guestCustomization.computerName being too long
+ group = "vcd";
+ }
+
+ @Override
+ public void testOptionToNotBlock() {
+ // start call has to block until deploy
}
@Override
protected Module getSshModule() {
return new SshjSshClientModule();
}
-
+
// vcloud does not support metadata
@Override
protected void checkUserMetadataInNodeEquals(NodeMetadata node, ImmutableMap<String, String> userMetadata) {
assert node.getUserMetadata().equals(ImmutableMap.<String, String> of()) : String.format(
- "node userMetadata did not match %s %s", userMetadata, node);
- }
-
- @Override
- public void testListNodes() throws Exception {
- for (ComputeMetadata node : client.listNodes()) {
- assert node.getProviderId() != null;
- assert node.getLocation() != null;
- assertEquals(node.getType(), ComputeType.NODE);
- NodeMetadata allData = client.getNodeMetadata(node.getId());
- System.out.println(allData.getHardware());
- RestContext<VCloudClient, VCloudAsyncClient> tmContext = new ComputeServiceContextFactory(
- setupRestProperties()).createContext(provider, identity, credential, ImmutableSet.<Module> of(),
- setupProperties()).getProviderSpecificContext();
- VApp vApp = tmContext.getApi().getVAppClient().findVAppInOrgVDCNamed(null, null, allData.getName());
- assertEquals(vApp.getName(), allData.getName());
- }
+ "node userMetadata did not match %s %s", userMetadata, node);
}
- @Test(enabled = true, dependsOnMethods = "testSuspendResume")
- @Override
- public void testGetNodesWithDetails() throws Exception {
- super.testGetNodesWithDetails();
- }
-
- @Test(enabled = true, dependsOnMethods = { "testListNodes", "testGetNodesWithDetails" })
- @Override
- public void testDestroyNodes() {
- super.testDestroyNodes();
- }
}
\ No newline at end of file
diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/functions/ListImagesInVCloudExpectTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/functions/ListImagesInVCloudExpectTest.java
new file mode 100644
index 0000000..083ba3f
--- /dev/null
+++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/functions/ListImagesInVCloudExpectTest.java
@@ -0,0 +1,88 @@
+/**
+ * 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.vcloud.compute.functions;
+
+import static org.testng.Assert.assertEquals;
+
+import java.net.URI;
+import java.util.Set;
+
+import org.jclouds.cim.OSType;
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.domain.CIMOperatingSystem;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.ImageBuilder;
+import org.jclouds.domain.Location;
+import org.jclouds.domain.LocationBuilder;
+import org.jclouds.domain.LocationScope;
+import org.jclouds.domain.LoginCredentials;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.location.suppliers.JustProvider;
+import org.jclouds.vcloud.compute.BaseVCloudComputeServiceExpectTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+@Test(singleThreaded = true, testName = "ListImagesInVCloudExpectTest")
+public class ListImagesInVCloudExpectTest extends BaseVCloudComputeServiceExpectTest {
+
+ public void testListImagesUsingVCloud1_0ApiOnServerRunningVCloudDirector1_5ReturnsImageWithLocationForVAppTemplateInVDC() throws Exception {
+ ComputeService compute = requestsSendResponses(ImmutableMap.<HttpRequest, HttpResponse>builder()
+ .put(versionsRequest, versionsResponseFromVCD1_5)
+ .put(version1_0LoginRequest, successfulVersion1_0LoginResponseFromVCD1_5WithSingleOrg)
+ .put(version1_0GetOrgRequest, successfulVersion1_0GetOrgResponseFromVCD1_5WithSingleTasksListVDCAndNetwork)
+ .put(version1_0GetCatalogRequest, successfulVersion1_0GetCatalogResponseFromVCD1_5WithSingleTemplate)
+ .put(version1_0GetCatalogItemRequest, successfulVersion1_0GetCatalogItemResponseFromVCD1_5ForTemplate)
+ .put(version1_0GetVDCRequest, successfulVersion1_0GetVDCResponseFromVCD1_5WithSingleTemplateAndNetwork)
+ .put(version1_0GetVAppTemplateRequest, successfulVersion1_0GetVAppTemplateResponseFromVCD1_5WithSingleVMAndVDCParent)
+ .put(version1_0GetOVFForVAppTemplateRequest, successfulVersion1_0GetOVFForVAppTemplateResponseFromVCD1_5WithSingleVM)
+ .build());
+
+ Location provider = Iterables.getOnlyElement(compute.getContext().utils().injector().getInstance(JustProvider.class).get());
+
+ Location orgLocation = new LocationBuilder().id(ENDPOINT + "/v1.0/org/" + orgId).scope(LocationScope.REGION)
+ .description("jclouds").parent(provider).build();
+
+ Location vdcLocation = new LocationBuilder().id(ENDPOINT + "/v1.0/vdc/" + vdcId).scope(LocationScope.ZONE)
+ .description("orgVDC-jclouds-Tier1-PAYG").parent(orgLocation).build();
+
+ Set<? extends Image> currentImages = compute.listImages();
+ assertEquals(compute.listImages().size(), 1);
+ Image onlyImage = Iterables.get(currentImages, 0);
+
+
+ Image expectedImage = new ImageBuilder()
+ .ids(ENDPOINT + "/v1.0/vAppTemplate/" + templateId)
+ .uri(URI.create(ENDPOINT + "/v1.0/vAppTemplate/" + templateId))
+ .name("UbuntuServer-x64-2GB")
+ .operatingSystem(new CIMOperatingSystem(OSType.UBUNTU_64, "", null, "Ubuntu Linux (64-bit)"))
+ // TODO: this looks like a bug, as it says network interfaces
+ .description("This is a special place-holder used for disconnected network interfaces.")
+ .defaultCredentials(LoginCredentials.builder().identity("root").build())
+ .location(vdcLocation).build();
+
+ assertEquals(onlyImage, expectedImage);
+ }
+}
diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOnExpectTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOnExpectTest.java
new file mode 100644
index 0000000..7cd597f
--- /dev/null
+++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOnExpectTest.java
@@ -0,0 +1,72 @@
+/**
+ * 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.vcloud.compute.strategy;
+
+import static org.testng.Assert.assertEquals;
+
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials;
+import org.jclouds.domain.LoginCredentials;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.vcloud.compute.BaseVCloudComputeServiceExpectTest;
+import org.jclouds.vcloud.domain.VApp;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+@Test(singleThreaded = true, testName = "InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOnExpectTest")
+public class InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOnExpectTest extends
+ BaseVCloudComputeServiceExpectTest {
+
+ // TODO: finish me
+ @Test(enabled = false)
+ public void testCreateNodeUsingVCloud1_0ApiAgainstVCloudDirector1_5WhenVAppTemplateHasNetworkNamedNone()
+ throws Exception {
+ ComputeService compute = requestsSendResponses(ImmutableMap.<HttpRequest, HttpResponse> builder().put(
+ versionsRequest, versionsResponseFromVCD1_5).put(version1_0LoginRequest,
+ successfulVersion1_0LoginResponseFromVCD1_5WithSingleOrg).put(version1_0GetOrgRequest,
+ successfulVersion1_0GetOrgResponseFromVCD1_5WithSingleTasksListVDCAndNetwork).put(
+ version1_0GetCatalogRequest, successfulVersion1_0GetCatalogResponseFromVCD1_5WithSingleTemplate).put(
+ version1_0GetCatalogItemRequest, successfulVersion1_0GetCatalogItemResponseFromVCD1_5ForTemplate).put(
+ version1_0GetVDCRequest, successfulVersion1_0GetVDCResponseFromVCD1_5WithSingleTemplateAndNetwork).put(
+ version1_0GetVAppTemplateRequest,
+ successfulVersion1_0GetVAppTemplateResponseFromVCD1_5WithSingleVMAndVDCParent).put(
+ version1_0GetOVFForVAppTemplateRequest,
+ successfulVersion1_0GetOVFForVAppTemplateResponseFromVCD1_5WithSingleVM).build());
+
+ InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn starter = compute.getContext()
+ .utils().injector().getInstance(
+ InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn.class);
+
+ String group = "group";
+ String name = "group-abcd";
+
+ NodeAndInitialCredentials<VApp> appAndCreds = starter.createNodeWithGroupEncodedIntoName(group, name, compute
+ .templateBuilder().build());
+
+ assertEquals(appAndCreds.getNode().getName(), name);
+ assertEquals(appAndCreds.getCredentials(), LoginCredentials.builder().user("root").password("fromVApp").build());
+
+ }
+}
diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/features/CatalogClientLiveTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/features/CatalogClientLiveTest.java
index 5fc3edd..b9ea2a4 100644
--- a/apis/vcloud/src/test/java/org/jclouds/vcloud/features/CatalogClientLiveTest.java
+++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/features/CatalogClientLiveTest.java
@@ -43,6 +43,7 @@
@Test
public void testFindCatalogIsWriteable() throws Exception {
- assertEquals(getVCloudApi().getCatalogClient().findCatalogInOrgNamed(null, null).isReadOnly(), false);
+ // default catalog should be the public one, unless we are in vCloud 1.0.0 where public catalogs don't work
+ assertEquals(getVCloudApi().getCatalogClient().findCatalogInOrgNamed(null, null).isReadOnly(), buildVersion.startsWith("1.5"));
}
}
\ No newline at end of file
diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/features/VmClientLiveTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/features/VmClientLiveTest.java
index d1014fe..eee3b7e 100644
--- a/apis/vcloud/src/test/java/org/jclouds/vcloud/features/VmClientLiveTest.java
+++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/features/VmClientLiveTest.java
@@ -98,7 +98,7 @@
public void testExtendedOptionsWithCustomizationScript() throws Exception {
String PARSE_VMTOOLSD = "vmtoolsd --cmd=\"info-get guestinfo.ovfenv\" |grep vCloud_CustomizationInfo|sed 's/.*value=\"\\(.*\\)\".*/\\1/g'";
- String group = prefix + "customize";
+ String group = prefix + "cus";
NodeMetadata node = null;
try {
diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/handlers/ParseVCloudErrorFromHttpResponseTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/handlers/ParseVCloudErrorFromHttpResponseTest.java
index 996994b..0a79e44 100644
--- a/apis/vcloud/src/test/java/org/jclouds/vcloud/handlers/ParseVCloudErrorFromHttpResponseTest.java
+++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/handlers/ParseVCloudErrorFromHttpResponseTest.java
@@ -54,6 +54,19 @@
}
@Test
+ public void testGet403NoAcessToEntitySetsResourceNotFoundExceptionOnAPI1_0AgainstVCD1_5() {
+ assertCodeMakes(
+ "GET",
+ URI.create("https://mycloud.greenhousedata.com/api/v1.0/vApp/vapp-d3a1f2cd-d07b-4ddc-bf7b-fb7468b4d95a"),
+ 403,
+ "HTTP/1.1 403",
+ // NOTE VCD 1.5 appends the api version to the media type
+ VCloudMediaType.ERROR_XML + ";1.0",
+ "<Error xmlns=\"http://www.vmware.com/vcloud/v1\" minorErrorCode=\"ACCESS_TO_RESOURCE_IS_FORBIDDEN\" message=\"No access to entity "(com.vmware.vcloud.entity.vapp:d3a1f2cd-d07b-4ddc-bf7b-fb7468b4d95a)".\" majorErrorCode=\"403\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.vmware.com/vcloud/v1 http://mycloud.greenhousedata.com/api/v1.0/schema/master.xsd\"></Error>",
+ ResourceNotFoundException.class);
+ }
+
+ @Test
public void testDelete404SetsHttpResponseException() {
assertCodeMakes("DELETE", URI.create("https://services.vcloudexpress.terremark.com/api/v0.8a-ext1.6/vdc/32"),
404, "", "", HttpResponseException.class);
diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudAsyncClientTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudAsyncClientTest.java
index db0ce26..84f2ad0 100644
--- a/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudAsyncClientTest.java
+++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudAsyncClientTest.java
@@ -32,6 +32,8 @@
import org.jclouds.http.HttpRequest;
import org.jclouds.http.RequiresHttp;
+import org.jclouds.ovf.Envelope;
+import org.jclouds.ovf.xml.EnvelopeHandlerTest;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.RestClientTest;
@@ -44,6 +46,7 @@
import org.jclouds.vcloud.domain.Org;
import org.jclouds.vcloud.domain.ReferenceType;
import org.jclouds.vcloud.domain.Task;
+import org.jclouds.vcloud.domain.VAppTemplate;
import org.jclouds.vcloud.domain.VCloudSession;
import org.jclouds.vcloud.domain.VDC;
import org.jclouds.vcloud.domain.VDCStatus;
@@ -53,15 +56,19 @@
import org.jclouds.vcloud.domain.internal.ReferenceTypeImpl;
import org.jclouds.vcloud.domain.internal.VDCImpl;
import org.jclouds.vcloud.filters.SetVCloudTokenCookie;
+import org.jclouds.vcloud.xml.VAppTemplateHandlerTest;
import org.testng.annotations.Test;
+import com.google.common.base.Functions;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
+import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.AbstractModule;
import com.google.inject.Module;
+import com.google.inject.TypeLiteral;
/**
* Tests behavior of {@code VCloudAsyncClient}
@@ -182,6 +189,16 @@
bind(OrgCatalogSupplier.class).to(TestOrgCatalogSupplier.class);
bind(OrgCatalogItemSupplier.class).to(TestOrgCatalogItemSupplier.class);
}
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void bindCacheLoaders() {
+ bind(new TypeLiteral<CacheLoader<URI, VAppTemplate>>() {
+ }).toInstance((CacheLoader) CacheLoader.from(Functions.constant(VAppTemplateHandlerTest.parseTemplate())));
+
+ bind(new TypeLiteral<CacheLoader<URI, Envelope>>() {
+ }).toInstance((CacheLoader) CacheLoader.from(Functions.constant(EnvelopeHandlerTest.parseEnvelope())));
+ }
@Override
protected Supplier<Map<String, Map<String, org.jclouds.vcloud.domain.VDC>>> provideOrgVDCSupplierCache(
diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudClientLiveTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudClientLiveTest.java
index 4ba2dbe..8b3b86b 100644
--- a/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudClientLiveTest.java
+++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudClientLiveTest.java
@@ -42,7 +42,8 @@
*/
@Test(groups = "live", enabled = true, singleThreaded = true)
public abstract class BaseVCloudClientLiveTest extends BaseVersionedServiceLiveTest {
- protected String prefix = System.getProperty("user.name");
+ // username is too long for name constraints
+ protected String prefix = "vcd";
protected ComputeService client;
diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptionsTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptionsTest.java
index 1971f31..e8b4943 100644
--- a/apis/vcloud/src/test/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptionsTest.java
+++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptionsTest.java
@@ -19,7 +19,6 @@
package org.jclouds.vcloud.options;
import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.addNetworkConfig;
-import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.customizeOnInstantiate;
import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.description;
import static org.testng.Assert.assertEquals;
@@ -63,19 +62,6 @@
}
@Test
- public void testCustomizeOnInstantiate() {
- InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions();
- options.customizeOnInstantiate(true);
- assertEquals(options.shouldCustomizeOnInstantiate(), new Boolean(true));
- }
-
- @Test
- public void testCustomizeOnInstantiateStatic() {
- InstantiateVAppTemplateOptions options = customizeOnInstantiate(true);
- assertEquals(options.shouldCustomizeOnInstantiate(), new Boolean(true));
- }
-
- @Test
public void testDescription() {
InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions();
options.description("foo");
diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppHandlerTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppHandlerTest.java
index 30292b7..d953600 100644
--- a/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppHandlerTest.java
+++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppHandlerTest.java
@@ -71,6 +71,7 @@
.create("https://vcenterprise.bluelock.com/api/v1.0/vdc/1014839439")));
assertEquals(result.getTasks(), ImmutableList.of());
assert result.isOvfDescriptorUploaded();
+ assert result.getNetworkSection() != null;
Vm vm = Iterables.getOnlyElement(result.getChildren());
VmHandlerTest.checkVm(vm);
}
diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppTemplateHandlerTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppTemplateHandlerTest.java
index 024ea9e..9bfe3b8 100644
--- a/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppTemplateHandlerTest.java
+++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppTemplateHandlerTest.java
@@ -54,10 +54,7 @@
public class VAppTemplateHandlerTest {
public void testUbuntuTemplate() {
- InputStream is = getClass().getResourceAsStream("/vAppTemplate.xml");
- Injector injector = Guice.createInjector(new SaxParserModule());
- Factory factory = injector.getInstance(ParseSax.Factory.class);
- VAppTemplate result = factory.create(injector.getInstance(VAppTemplateHandler.class)).parse(is);
+ VAppTemplate result = parseTemplate();
assertEquals(result.getName(), "Ubuntu Template");
assertEquals(result.getHref(), URI
.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/vappTemplate-1201908921"));
@@ -118,6 +115,14 @@
}
+ public static VAppTemplate parseTemplate() {
+ InputStream is = VAppTemplateHandlerTest.class.getResourceAsStream("/vAppTemplate.xml");
+ Injector injector = Guice.createInjector(new SaxParserModule());
+ Factory factory = injector.getInstance(ParseSax.Factory.class);
+ VAppTemplate result = factory.create(injector.getInstance(VAppTemplateHandler.class)).parse(is);
+ return result;
+ }
+
public void testCopyingTemplate() {
InputStream is = getClass().getResourceAsStream("/vAppTemplate-copying.xml");
Injector injector = Guice.createInjector(new SaxParserModule());
@@ -148,4 +153,14 @@
assertEquals(result.getNetworkSection(), null);
}
+
+ public void testVAppTemplateWithNewlinesAndNamespacedElements() {
+ InputStream is = getClass().getResourceAsStream("/vAppTemplate1.0-vcd15_withNewlines.xml");
+ Injector injector = Guice.createInjector(new SaxParserModule());
+ Factory factory = injector.getInstance(ParseSax.Factory.class);
+
+ factory.create(injector.getInstance(VAppTemplateHandler.class)).parse(is);
+ }
+
+
}
diff --git a/apis/vcloud/src/test/resources/catalog1.0-vcd15.xml b/apis/vcloud/src/test/resources/catalog1.0-vcd15.xml
new file mode 100644
index 0000000..0208e59
--- /dev/null
+++ b/apis/vcloud/src/test/resources/catalog1.0-vcd15.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Catalog xmlns="http://www.vmware.com/vcloud/v1" name="jclouds" type="application/vnd.vmware.vcloud.catalog+xml" href="https://zone.myvcloud.com/api/v1.0/catalog/3155f393-1e1d-4572-8c9c-d76f72ddb658" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1 https://zone.myvcloud.com/api/v1.0/schema/master.xsd">
+ <Link rel="up" type="application/vnd.vmware.vcloud.org+xml" href="https://zone.myvcloud.com/api/v1.0/org/c076f90a-397a-49fa-89b8-b294c1599cd0"/>
+ <Link rel="add" type="application/vnd.vmware.vcloud.catalogItem+xml" href="https://zone.myvcloud.com/api/v1.0/catalog/3155f393-1e1d-4572-8c9c-d76f72ddb658/catalogItems"/>
+ <CatalogItems>
+ <CatalogItem type="application/vnd.vmware.vcloud.catalogItem+xml" name="UbuntuServer-x64-2GB" href="https://zone.myvcloud.com/api/v1.0/catalogItem/ceb369f7-1d07-4e32-9dbd-ebb5aa6ca55c"/>
+ </CatalogItems>
+ <IsPublished>false</IsPublished>
+</Catalog>
\ No newline at end of file
diff --git a/apis/vcloud/src/test/resources/catalogItem1.0-vcd15.xml b/apis/vcloud/src/test/resources/catalogItem1.0-vcd15.xml
new file mode 100644
index 0000000..b344071
--- /dev/null
+++ b/apis/vcloud/src/test/resources/catalogItem1.0-vcd15.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CatalogItem xmlns="http://www.vmware.com/vcloud/v1" name="UbuntuServer-x64-2GB" type="application/vnd.vmware.vcloud.catalogItem+xml" href="https://zone.myvcloud.com/api/v1.0/catalogItem/ceb369f7-1d07-4e32-9dbd-ebb5aa6ca55c" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1 https://zone.myvcloud.com/api/v1.0/schema/master.xsd">
+ <Link rel="up" type="application/vnd.vmware.vcloud.catalog+xml" href="https://zone.myvcloud.com/api/v1.0/catalog/3155f393-1e1d-4572-8c9c-d76f72ddb658"/>
+ <Link rel="edit" type="application/vnd.vmware.vcloud.catalogItem+xml" href="https://zone.myvcloud.com/api/v1.0/catalogItem/ceb369f7-1d07-4e32-9dbd-ebb5aa6ca55c"/>
+ <Link rel="remove" href="https://zone.myvcloud.com/api/v1.0/catalogItem/ceb369f7-1d07-4e32-9dbd-ebb5aa6ca55c"/>
+ <Description> </Description>
+ <Entity type="application/vnd.vmware.vcloud.vAppTemplate+xml" name="UbuntuServer-x64-2GB" href="https://zone.myvcloud.com/api/v1.0/vAppTemplate/vappTemplate-51891b97-c5dd-47dc-a687-aabae354f728"/>
+</CatalogItem>
\ No newline at end of file
diff --git a/apis/vcloud/src/test/resources/instantiationparams-customization.xml b/apis/vcloud/src/test/resources/instantiationparams-customization.xml
deleted file mode 100644
index 9df9961..0000000
--- a/apis/vcloud/src/test/resources/instantiationparams-customization.xml
+++ /dev/null
@@ -1 +0,0 @@
-<InstantiateVAppTemplateParams xmlns="http://www.vmware.com/vcloud/v1" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" deploy="true" name="my-vapp" powerOn="true"><InstantiationParams><NetworkConfigSection><ovf:Info>Configuration parameters for logical networks</ovf:Info><NetworkConfig networkName="vAppNet-vApp Internal"><Configuration><ParentNetwork href="https://vcenterprise.bluelock.com/api/v1.0/network/1990"/><FenceMode>bridged</FenceMode></Configuration></NetworkConfig></NetworkConfigSection></InstantiationParams><Source href="https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3"/><AllEULAsAccepted>true</AllEULAsAccepted></InstantiateVAppTemplateParams>
\ No newline at end of file
diff --git a/apis/vcloud/src/test/resources/org1.0-vcd15.xml b/apis/vcloud/src/test/resources/org1.0-vcd15.xml
new file mode 100644
index 0000000..d0ca5b7
--- /dev/null
+++ b/apis/vcloud/src/test/resources/org1.0-vcd15.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Org xmlns="http://www.vmware.com/vcloud/v1" name="jclouds" type="application/vnd.vmware.vcloud.org+xml" href="https://zone.myvcloud.com/api/v1.0/org/c076f90a-397a-49fa-89b8-b294c1599cd0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1 https://zone.myvcloud.com/api/v1.0/schema/master.xsd">
+ <Link rel="down" type="application/vnd.vmware.vcloud.vdc+xml" name="orgVDC-jclouds-Tier1-PAYG" href="https://zone.myvcloud.com/api/v1.0/vdc/e9cd3387-ac57-4d27-a481-9bee75e0690f"/>
+ <Link rel="down" type="application/vnd.vmware.vcloud.tasksList+xml" href="https://zone.myvcloud.com/api/v1.0/tasksList/c076f90a-397a-49fa-89b8-b294c1599cd0"/>
+ <Link rel="down" type="application/vnd.vmware.vcloud.catalog+xml" name="jclouds" href="https://zone.myvcloud.com/api/v1.0/catalog/3155f393-1e1d-4572-8c9c-d76f72ddb658"/>
+ <Link rel="down" type="application/vnd.vmware.vcloud.controlAccess+xml" href="https://zone.myvcloud.com/api/v1.0/org/c076f90a-397a-49fa-89b8-b294c1599cd0/catalog/3155f393-1e1d-4572-8c9c-d76f72ddb658/controlAccess/"/>
+ <Link rel="controlAccess" type="application/vnd.vmware.vcloud.controlAccess+xml" href="https://zone.myvcloud.com/api/v1.0/org/c076f90a-397a-49fa-89b8-b294c1599cd0/catalog/3155f393-1e1d-4572-8c9c-d76f72ddb658/action/controlAccess"/>
+ <Link rel="down" type="application/vnd.vmware.vcloud.network+xml" name="orgNet-jclouds-External" href="https://zone.myvcloud.com/api/v1.0/network/b466c0c5-8a5c-4335-b703-a2e2e6b5f3e1"/>
+ <Description>Customer jclouds</Description>
+ <FullName>jclouds</FullName>
+</Org>
\ No newline at end of file
diff --git a/apis/vcloud/src/test/resources/orgList1.0-vcd15.xml b/apis/vcloud/src/test/resources/orgList1.0-vcd15.xml
new file mode 100644
index 0000000..40f3cbe
--- /dev/null
+++ b/apis/vcloud/src/test/resources/orgList1.0-vcd15.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<OrgList xmlns="http://www.vmware.com/vcloud/v1" type="application/vnd.vmware.vcloud.orgList+xml" href="https://zone.myvcloud.com/api/v1.0/org/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1 https://zone.myvcloud.com/api/v1.0/schema/master.xsd">
+ <Org type="application/vnd.vmware.vcloud.org+xml" name="jclouds" href="https://zone.myvcloud.com/api/v1.0/org/c076f90a-397a-49fa-89b8-b294c1599cd0"/>
+</OrgList>
\ No newline at end of file
diff --git a/apis/vcloud/src/test/resources/ovf-ubuntu64.xml b/apis/vcloud/src/test/resources/ovf-ubuntu64.xml
new file mode 100644
index 0000000..7679573
--- /dev/null
+++ b/apis/vcloud/src/test/resources/ovf-ubuntu64.xml
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ovf:Envelope xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" xmlns:vcloud="http://www.vmware.com/vcloud/v1" xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2.22.0/CIM_VirtualSystemSettingData.xsd http://schemas.dmtf.org/ovf/envelope/1 http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2.22.0/CIM_ResourceAllocationSettingData.xsd http://www.vmware.com/vcloud/v1 https://zone.myvcloud.com/api/v1.0/schema/master.xsd">
+ <ovf:References/>
+ <ovf:NetworkSection>
+ <ovf:Info>The list of logical networks</ovf:Info>
+ <ovf:Network ovf:name="none">
+ <ovf:Description>This is a special place-holder used for disconnected network interfaces.</ovf:Description>
+ </ovf:Network>
+ </ovf:NetworkSection>
+ <vcloud:NetworkConfigSection ovf:required="false">
+ <ovf:Info>The configuration parameters for logical networks</ovf:Info>
+ <vcloud:NetworkConfig networkName="none">
+ <vcloud:Description>This is a special place-holder used for disconnected network interfaces.</vcloud:Description>
+ <vcloud:Configuration>
+ <vcloud:IpScope>
+ <vcloud:IsInherited>false</vcloud:IsInherited>
+ <vcloud:Gateway>196.254.254.254</vcloud:Gateway>
+ <vcloud:Netmask>255.255.0.0</vcloud:Netmask>
+ <vcloud:Dns1>196.254.254.254</vcloud:Dns1>
+ </vcloud:IpScope>
+ <vcloud:FenceMode>isolated</vcloud:FenceMode>
+ </vcloud:Configuration>
+ <vcloud:IsDeployed>false</vcloud:IsDeployed>
+ </vcloud:NetworkConfig>
+ </vcloud:NetworkConfigSection>
+ <vcloud:LeaseSettingsSection ovf:required="false">
+ <ovf:Info>Lease settings section</ovf:Info>
+ <vcloud:DeploymentLeaseInSeconds>0</vcloud:DeploymentLeaseInSeconds>
+ <vcloud:StorageLeaseInSeconds>5184000</vcloud:StorageLeaseInSeconds>
+ <vcloud:StorageLeaseExpiration>2012-03-12T17:40:44.491-06:00</vcloud:StorageLeaseExpiration>
+ </vcloud:LeaseSettingsSection>
+ <vcloud:CustomizationSection ovf:required="false">
+ <ovf:Info>VApp template customization section</ovf:Info>
+ <vcloud:CustomizeOnInstantiate>true</vcloud:CustomizeOnInstantiate>
+ </vcloud:CustomizationSection>
+ <ovf:VirtualSystem ovf:id="UbuntuServer-x64-2GB">
+ <ovf:Info>A virtual machine: </ovf:Info>
+ <ovf:Name>UbuntuServer-x64-2GB</ovf:Name>
+ <ovf:OperatingSystemSection xmlns:vmw="http://www.vmware.com/schema/ovf" ovf:id="94" vmw:osType="ubuntu64Guest">
+ <ovf:Info>Specifies the operating system installed</ovf:Info>
+ <ovf:Description>Ubuntu Linux (64-bit)</ovf:Description>
+ </ovf:OperatingSystemSection>
+ <ovf:VirtualHardwareSection>
+ <ovf:Info>Virtual hardware requirements</ovf:Info>
+ <ovf:System>
+ <vssd:ElementName>Virtual Hardware Family</vssd:ElementName>
+ <vssd:InstanceID>0</vssd:InstanceID>
+ <vssd:VirtualSystemIdentifier>UbuntuServer-x64-2GB</vssd:VirtualSystemIdentifier>
+ <vssd:VirtualSystemType>vmx-07</vssd:VirtualSystemType>
+ </ovf:System>
+ <ovf:Item>
+ <rasd:Address>00:50:56:01:02:9f</rasd:Address>
+ <rasd:AddressOnParent>0</rasd:AddressOnParent>
+ <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
+ <rasd:Connection vcloud:primaryNetworkConnection="true" vcloud:ipAddressingMode="NONE">none</rasd:Connection>
+ <rasd:Description>PCNet32 ethernet adapter</rasd:Description>
+ <rasd:ElementName>Network adapter 0</rasd:ElementName>
+ <rasd:InstanceID>1</rasd:InstanceID>
+ <rasd:ResourceSubType>PCNet32</rasd:ResourceSubType>
+ <rasd:ResourceType>10</rasd:ResourceType>
+ </ovf:Item>
+ <ovf:Item>
+ <rasd:Address>0</rasd:Address>
+ <rasd:Description>SCSI Controller</rasd:Description>
+ <rasd:ElementName>SCSI Controller 0</rasd:ElementName>
+ <rasd:InstanceID>2</rasd:InstanceID>
+ <rasd:ResourceSubType>lsilogic</rasd:ResourceSubType>
+ <rasd:ResourceType>6</rasd:ResourceType>
+ </ovf:Item>
+ <ovf:Item>
+ <rasd:AddressOnParent>0</rasd:AddressOnParent>
+ <rasd:Description>Hard disk</rasd:Description>
+ <rasd:ElementName>Hard disk 1</rasd:ElementName>
+ <rasd:HostResource vcloud:capacity="2048" vcloud:busType="6" vcloud:busSubType="lsilogic"/>
+ <rasd:InstanceID>2000</rasd:InstanceID>
+ <rasd:Parent>2</rasd:Parent>
+ <rasd:ResourceType>17</rasd:ResourceType>
+ </ovf:Item>
+ <ovf:Item>
+ <rasd:Address>0</rasd:Address>
+ <rasd:Description>IDE Controller</rasd:Description>
+ <rasd:ElementName>IDE Controller 0</rasd:ElementName>
+ <rasd:InstanceID>3</rasd:InstanceID>
+ <rasd:ResourceType>5</rasd:ResourceType>
+ </ovf:Item>
+ <ovf:Item>
+ <rasd:AddressOnParent>0</rasd:AddressOnParent>
+ <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
+ <rasd:Description>CD/DVD Drive</rasd:Description>
+ <rasd:ElementName>CD/DVD Drive 1</rasd:ElementName>
+ <rasd:HostResource/>
+ <rasd:InstanceID>3000</rasd:InstanceID>
+ <rasd:Parent>3</rasd:Parent>
+ <rasd:ResourceType>15</rasd:ResourceType>
+ </ovf:Item>
+ <ovf:Item>
+ <rasd:AddressOnParent>0</rasd:AddressOnParent>
+ <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
+ <rasd:Description>Floppy Drive</rasd:Description>
+ <rasd:ElementName>Floppy Drive 1</rasd:ElementName>
+ <rasd:HostResource/>
+ <rasd:InstanceID>8000</rasd:InstanceID>
+ <rasd:ResourceType>14</rasd:ResourceType>
+ </ovf:Item>
+ <ovf:Item>
+ <rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>
+ <rasd:Description>Number of Virtual CPUs</rasd:Description>
+ <rasd:ElementName>1 virtual CPU(s)</rasd:ElementName>
+ <rasd:InstanceID>4</rasd:InstanceID>
+ <rasd:Reservation>0</rasd:Reservation>
+ <rasd:ResourceType>3</rasd:ResourceType>
+ <rasd:VirtualQuantity>1</rasd:VirtualQuantity>
+ <rasd:Weight>0</rasd:Weight>
+ </ovf:Item>
+ <ovf:Item>
+ <rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>
+ <rasd:Description>Memory Size</rasd:Description>
+ <rasd:ElementName>256 MB of memory</rasd:ElementName>
+ <rasd:InstanceID>5</rasd:InstanceID>
+ <rasd:Reservation>0</rasd:Reservation>
+ <rasd:ResourceType>4</rasd:ResourceType>
+ <rasd:VirtualQuantity>256</rasd:VirtualQuantity>
+ <rasd:Weight>0</rasd:Weight>
+ </ovf:Item>
+ </ovf:VirtualHardwareSection>
+ <vcloud:NetworkConnectionSection ovf:required="false">
+ <ovf:Info>Specifies the available VM network connections</ovf:Info>
+ <vcloud:PrimaryNetworkConnectionIndex>0</vcloud:PrimaryNetworkConnectionIndex>
+ <vcloud:NetworkConnection network="none">
+ <vcloud:NetworkConnectionIndex>0</vcloud:NetworkConnectionIndex>
+ <vcloud:IsConnected>false</vcloud:IsConnected>
+ <vcloud:MACAddress>00:50:56:01:02:9f</vcloud:MACAddress>
+ <vcloud:IpAddressAllocationMode>NONE</vcloud:IpAddressAllocationMode>
+ </vcloud:NetworkConnection>
+ </vcloud:NetworkConnectionSection>
+ <vcloud:GuestCustomizationSection ovf:required="false">
+ <ovf:Info>Specifies Guest OS Customization Settings</ovf:Info>
+ <vcloud:Enabled>true</vcloud:Enabled>
+ <vcloud:ChangeSid>false</vcloud:ChangeSid>
+ <vcloud:JoinDomainEnabled>false</vcloud:JoinDomainEnabled>
+ <vcloud:UseOrgSettings>false</vcloud:UseOrgSettings>
+ <vcloud:AdminPasswordEnabled>true</vcloud:AdminPasswordEnabled>
+ <vcloud:AdminPasswordAuto>true</vcloud:AdminPasswordAuto>
+ <vcloud:ResetPasswordRequired>false</vcloud:ResetPasswordRequired>
+ <vcloud:ComputerName>UbuntuServer</vcloud:ComputerName>
+ </vcloud:GuestCustomizationSection>
+ </ovf:VirtualSystem>
+</ovf:Envelope>
\ No newline at end of file
diff --git a/apis/vcloud/src/test/resources/template1.0-vcd15.xml b/apis/vcloud/src/test/resources/template1.0-vcd15.xml
new file mode 100644
index 0000000..35393ee
--- /dev/null
+++ b/apis/vcloud/src/test/resources/template1.0-vcd15.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<VAppTemplate xmlns="http://www.vmware.com/vcloud/v1" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" ovfDescriptorUploaded="true" status="8" name="UbuntuServer-x64-2GB" type="application/vnd.vmware.vcloud.vAppTemplate+xml" href="https://zone.myvcloud.com/api/v1.0/vAppTemplate/vappTemplate-51891b97-c5dd-47dc-a687-aabae354f728" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schemas.dmtf.org/ovf/envelope/1 http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd http://www.vmware.com/vcloud/v1 https://zone.myvcloud.com/api/v1.0/schema/master.xsd">
+ <Link rel="up" type="application/vnd.vmware.vcloud.vdc+xml" href="https://zone.myvcloud.com/api/v1.0/vdc/e9cd3387-ac57-4d27-a481-9bee75e0690f"/>
+ <Link rel="catalogItem" type="application/vnd.vmware.vcloud.catalogItem+xml" href="https://zone.myvcloud.com/api/v1.0/catalogItem/ceb369f7-1d07-4e32-9dbd-ebb5aa6ca55c"/>
+ <Link rel="remove" href="https://zone.myvcloud.com/api/v1.0/vAppTemplate/vappTemplate-51891b97-c5dd-47dc-a687-aabae354f728"/>
+ <Link rel="edit" type="application/vnd.vmware.vcloud.vAppTemplate+xml" href="https://zone.myvcloud.com/api/v1.0/vAppTemplate/vappTemplate-51891b97-c5dd-47dc-a687-aabae354f728"/>
+ <Link rel="enable" href="https://zone.myvcloud.com/api/v1.0/vAppTemplate/vappTemplate-51891b97-c5dd-47dc-a687-aabae354f728/action/enableDownload"/>
+ <Link rel="disable" href="https://zone.myvcloud.com/api/v1.0/vAppTemplate/vappTemplate-51891b97-c5dd-47dc-a687-aabae354f728/action/disableDownload"/>
+ <Link rel="ovf" type="text/xml" href="https://zone.myvcloud.com/api/v1.0/vAppTemplate/vappTemplate-51891b97-c5dd-47dc-a687-aabae354f728/ovf"/>
+ <Link rel="down" type="application/vnd.vmware.vcloud.owner+xml" href="https://zone.myvcloud.com/api/v1.0/vAppTemplate/vappTemplate-51891b97-c5dd-47dc-a687-aabae354f728/owner"/>
+ <Description/>
+ <Children>
+ <Vm name="UbuntuServer-x64-2GB" type="application/vnd.vmware.vcloud.vm+xml" href="https://zone.myvcloud.com/api/v1.0/vAppTemplate/vm-3aee3d0d-106a-4c63-8529-1edde335b212">
+ <Link rel="up" type="application/vnd.vmware.vcloud.vAppTemplate+xml" href="https://zone.myvcloud.com/api/v1.0/vAppTemplate/vappTemplate-51891b97-c5dd-47dc-a687-aabae354f728"/>
+ <Description/>
+ <NetworkConnectionSection type="application/vnd.vmware.vcloud.networkConnectionSection+xml" href="https://zone.myvcloud.com/api/v1.0/vAppTemplate/vm-3aee3d0d-106a-4c63-8529-1edde335b212/networkConnectionSection/" ovf:required="false">
+ <ovf:Info>Specifies the available VM network connections</ovf:Info>
+ <PrimaryNetworkConnectionIndex>0</PrimaryNetworkConnectionIndex>
+ <NetworkConnection network="none">
+ <NetworkConnectionIndex>0</NetworkConnectionIndex>
+ <IsConnected>false</IsConnected>
+ <MACAddress>00:50:56:01:02:9f</MACAddress>
+ <IpAddressAllocationMode>NONE</IpAddressAllocationMode>
+ </NetworkConnection>
+ </NetworkConnectionSection>
+ <GuestCustomizationSection type="application/vnd.vmware.vcloud.guestCustomizationSection+xml" href="https://zone.myvcloud.com/api/v1.0/vAppTemplate/vm-3aee3d0d-106a-4c63-8529-1edde335b212/guestCustomizationSection/" ovf:required="false">
+ <ovf:Info>Specifies Guest OS Customization Settings</ovf:Info>
+ <Enabled>true</Enabled>
+ <ChangeSid>false</ChangeSid>
+ <JoinDomainEnabled>false</JoinDomainEnabled>
+ <UseOrgSettings>false</UseOrgSettings>
+ <AdminPasswordEnabled>true</AdminPasswordEnabled>
+ <AdminPasswordAuto>true</AdminPasswordAuto>
+ <ResetPasswordRequired>false</ResetPasswordRequired>
+ <ComputerName>UbuntuServer</ComputerName>
+ </GuestCustomizationSection>
+ <VAppScopedLocalId>f114ade7-a63f-4f8b-b30b-44e9ff77e068</VAppScopedLocalId>
+ </Vm>
+ </Children>
+ <ovf:NetworkSection xmlns:vcloud="http://www.vmware.com/vcloud/v1" vcloud:href="https://zone.myvcloud.com/api/v1.0/vAppTemplate/vappTemplate-51891b97-c5dd-47dc-a687-aabae354f728/networkSection/" vcloud:type="application/vnd.vmware.vcloud.networkSection+xml">
+ <ovf:Info>The list of logical networks</ovf:Info>
+ <ovf:Network ovf:name="none">
+ <ovf:Description>This is a special place-holder used for disconnected network interfaces.</ovf:Description>
+ </ovf:Network>
+ </ovf:NetworkSection>
+ <NetworkConfigSection type="application/vnd.vmware.vcloud.networkConfigSection+xml" href="https://zone.myvcloud.com/api/v1.0/vAppTemplate/vappTemplate-51891b97-c5dd-47dc-a687-aabae354f728/networkConfigSection/" ovf:required="false">
+ <ovf:Info>The configuration parameters for logical networks</ovf:Info>
+ <NetworkConfig networkName="none">
+ <Description>This is a special place-holder used for disconnected network interfaces.</Description>
+ <Configuration>
+ <IpScope>
+ <IsInherited>false</IsInherited>
+ <Gateway>196.254.254.254</Gateway>
+ <Netmask>255.255.0.0</Netmask>
+ <Dns1>196.254.254.254</Dns1>
+ </IpScope>
+ <FenceMode>isolated</FenceMode>
+ </Configuration>
+ <IsDeployed>false</IsDeployed>
+ </NetworkConfig>
+ </NetworkConfigSection>
+ <LeaseSettingsSection type="application/vnd.vmware.vcloud.leaseSettingsSection+xml" href="https://zone.myvcloud.com/api/v1.0/vAppTemplate/vappTemplate-51891b97-c5dd-47dc-a687-aabae354f728/leaseSettingsSection/" ovf:required="false">
+ <ovf:Info>Lease settings section</ovf:Info>
+ <Link rel="edit" type="application/vnd.vmware.vcloud.leaseSettingsSection+xml" href="https://zone.myvcloud.com/api/v1.0/vAppTemplate/vappTemplate-51891b97-c5dd-47dc-a687-aabae354f728/leaseSettingsSection/"/>
+ <StorageLeaseInSeconds>5184000</StorageLeaseInSeconds>
+ <StorageLeaseExpiration>2012-03-12T17:40:44.491-06:00</StorageLeaseExpiration>
+ </LeaseSettingsSection>
+ <CustomizationSection type="application/vnd.vmware.vcloud.customizationSection+xml" href="https://zone.myvcloud.com/api/v1.0/vAppTemplate/vappTemplate-51891b97-c5dd-47dc-a687-aabae354f728/customizationSection/" ovf:required="false">
+ <ovf:Info>VApp template customization section</ovf:Info>
+ <CustomizeOnInstantiate>true</CustomizeOnInstantiate>
+ </CustomizationSection>
+</VAppTemplate>
\ No newline at end of file
diff --git a/apis/vcloud/src/test/resources/vAppTemplate1.0-vcd15_withNewlines.xml b/apis/vcloud/src/test/resources/vAppTemplate1.0-vcd15_withNewlines.xml
new file mode 100644
index 0000000..9f41d81
--- /dev/null
+++ b/apis/vcloud/src/test/resources/vAppTemplate1.0-vcd15_withNewlines.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<vcloud:VAppTemplate xmlns:vcloud="http://www.vmware.com/vcloud/v1" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" ovfDescriptorUploaded="true" status="8" name="Windows 2008 R2 Standard (base) with SP1" type="application/vnd.vmware.vcloud.vAppTempla
+te+xml" href="https://vcd.stratogen.net/api/v1.0/vAppTemplate/vappTemplate-f8ca27ba-c6ee-44bd-91a9-416f464cba80" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schemas.dmtf.org/ovf/envelope/1 http://schemas.dmtf.org/ovf
+/envelope/1/dsp8023_1.1.0.xsd http://www.vmware.com/vcloud/v1 http://109.233.49.135/api/v1.0/schema/master.xsd">
+ <vcloud:Link rel="catalogItem" type="application/vnd.vmware.vcloud.catalogItem+xml" href="https://vcd.stratogen.net/api/v1.0/catalogItem/16bdea08-f176-48ce-9fe8-fc2265fc1068"/>
+ <vcloud:Link rel="enable" href="https://vcd.stratogen.net/api/v1.0/vAppTemplate/vappTemplate-f8ca27ba-c6ee-44bd-91a9-416f464cba80/action/enableDownload"/>
+ <vcloud:Link rel="disable" href="https://vcd.stratogen.net/api/v1.0/vAppTemplate/vappTemplate-f8ca27ba-c6ee-44bd-91a9-416f464cba80/action/disableDownload"/>
+ <vcloud:Link rel="ovf" type="text/xml" href="https://vcd.stratogen.net/api/v1.0/vAppTemplate/vappTemplate-f8ca27ba-c6ee-44bd-91a9-416f464cba80/ovf"/>
+ <vcloud:Link rel="down" type="application/vnd.vmware.vcloud.owner+xml" href="https://vcd.stratogen.net/api/v1.0/vAppTemplate/vappTemplate-f8ca27ba-c6ee-44bd-91a9-416f464cba80/owner"/>
+ <vcloud:Description>Windows 2008 R2 Standard Edition
+Service Pack 1
+Internet Explorer 9</vcloud:Description>
+ <vcloud:Children>
+ <vcloud:Vm name="Windows 2008 R2 Standard (Base) with SP1" type="application/vnd.vmware.vcloud.vm+xml" href="https://vcd.stratogen.net/api/v1.0/vAppTemplate/vm-2ac49c8b-5cd9-428d-86da-24cfe9144b94">
+ <vcloud:Link rel="up" type="application/vnd.vmware.vcloud.vAppTemplate+xml" href="https://vcd.stratogen.net/api/v1.0/vAppTemplate/vappTemplate-f8ca27ba-c6ee-44bd-91a9-416f464cba80"/>
+ <vcloud:Description>Windows 2008 R2 Standard Edition
+Service Pack 1
+Internet Explorer 9</vcloud:Description>
+ <vcloud:NetworkConnectionSection type="application/vnd.vmware.vcloud.networkConnectionSection+xml" href="https://vcd.stratogen.net/api/v1.0/vAppTemplate/vm-2ac49c8b-5cd9-428d-86da-24cfe9144b94/networkConnectionSection/" ovf:required="false">
+ <ovf:Info>Specifies the available VM network connections</ovf:Info>
+ <vcloud:PrimaryNetworkConnectionIndex>0</vcloud:PrimaryNetworkConnectionIndex>
+ <vcloud:NetworkConnection network="StratoGen Ext Net">
+ <vcloud:NetworkConnectionIndex>0</vcloud:NetworkConnectionIndex>
+ <vcloud:IpAddress>212.54.128.56</vcloud:IpAddress>
+ <vcloud:IsConnected>true</vcloud:IsConnected>
+ <vcloud:MACAddress>00:50:56:01:0d:3c</vcloud:MACAddress>
+ <vcloud:IpAddressAllocationMode>POOL</vcloud:IpAddressAllocationMode>
+ </vcloud:NetworkConnection>
+ </vcloud:NetworkConnectionSection>
+ <vcloud:GuestCustomizationSection type="application/vnd.vmware.vcloud.guestCustomizationSection+xml" href="https://vcd.stratogen.net/api/v1.0/vAppTemplate/vm-2ac49c8b-5cd9-428d-86da-24cfe9144b94/guestCustomizationSection/" ovf:required="false">
+ <ovf:Info>Specifies Guest OS Customization Settings</ovf:Info>
+ <vcloud:Enabled>true</vcloud:Enabled>
+ <vcloud:ChangeSid>true</vcloud:ChangeSid>
+ <vcloud:JoinDomainEnabled>false</vcloud:JoinDomainEnabled>
+ <vcloud:UseOrgSettings>false</vcloud:UseOrgSettings>
+ <vcloud:AdminPasswordEnabled>true</vcloud:AdminPasswordEnabled>
+ <vcloud:AdminPasswordAuto>true</vcloud:AdminPasswordAuto>
+ <vcloud:AdminPassword>$6fEPL93</vcloud:AdminPassword>
+ <vcloud:ResetPasswordRequired>false</vcloud:ResetPasswordRequired>
+ <vcloud:ComputerName>Win2008r2Stand</vcloud:ComputerName>
+ </vcloud:GuestCustomizationSection>
+ <vcloud:VAppScopedLocalId>ac2ce03d-0491-46f7-afc6-37ffe5b30f74</vcloud:VAppScopedLocalId>
+ </vcloud:Vm>
+ </vcloud:Children>
+ <ovf:NetworkSection vcloud:href="https://vcd.stratogen.net/api/v1.0/vAppTemplate/vappTemplate-f8ca27ba-c6ee-44bd-91a9-416f464cba80/networkSection/" vcloud:type="application/vnd.vmware.vcloud.networkSection+xml">
+ <ovf:Info>The list of logical networks</ovf:Info>
+ <ovf:Network ovf:name="StratoGen Ext Net">
+ <ovf:Description/>
+ </ovf:Network>
+ </ovf:NetworkSection>
+ <vcloud:NetworkConfigSection type="application/vnd.vmware.vcloud.networkConfigSection+xml" href="https://vcd.stratogen.net/api/v1.0/vAppTemplate/vappTemplate-f8ca27ba-c6ee-44bd-91a9-416f464cba80/networkConfigSection/" ovf:required="false">
+ <ovf:Info>The configuration parameters for logical networks</ovf:Info>
+ <vcloud:NetworkConfig networkName="StratoGen Ext Net">
+ <vcloud:Description/>
+ <vcloud:Configuration>
+ <vcloud:IpScope>
+ <vcloud:IsInherited>true</vcloud:IsInherited>
+ <vcloud:Gateway>212.54.128.1</vcloud:Gateway>
+ <vcloud:Netmask>255.255.255.0</vcloud:Netmask>
+ <vcloud:Dns1>109.233.48.141</vcloud:Dns1>
+ <vcloud:Dns2>109.233.48.142</vcloud:Dns2>
+ <vcloud:IpRanges>
+ <vcloud:IpRange>
+ <vcloud:StartAddress>212.54.128.4</vcloud:StartAddress>
+ <vcloud:EndAddress>212.54.128.220</vcloud:EndAddress>
+ </vcloud:IpRange>
+ </vcloud:IpRanges>
+ </vcloud:IpScope>
+ <vcloud:FenceMode>bridged</vcloud:FenceMode>
+ <vcloud:Features>
+ <vcloud:DhcpService>
+ <vcloud:IsEnabled>false</vcloud:IsEnabled>
+ <vcloud:DefaultLeaseTime>3600</vcloud:DefaultLeaseTime>
+ <vcloud:MaxLeaseTime>7200</vcloud:MaxLeaseTime>
+ <vcloud:IpRange>
+ <vcloud:StartAddress>212.54.128.201</vcloud:StartAddress>
+ <vcloud:EndAddress>212.54.128.254</vcloud:EndAddress>
+ </vcloud:IpRange>
+ </vcloud:DhcpService>
+ <vcloud:FirewallService>
+ <vcloud:IsEnabled>true</vcloud:IsEnabled>
+ </vcloud:FirewallService>
+ <vcloud:NatService>
+ <vcloud:IsEnabled>true</vcloud:IsEnabled>
+ <vcloud:NatType>ipTranslation</vcloud:NatType>
+ <vcloud:Policy>allowTraffic</vcloud:Policy>
+ <vcloud:NatRule>
+ <vcloud:OneToOneVmRule>
+ <vcloud:MappingMode>automatic</vcloud:MappingMode>
+ <vcloud:VAppScopedVmId>ac2ce03d-0491-46f7-afc6-37ffe5b30f74</vcloud:VAppScopedVmId>
+ <vcloud:VmNicId>0</vcloud:VmNicId>
+ </vcloud:OneToOneVmRule>
+ </vcloud:NatRule>
+ </vcloud:NatService>
+ </vcloud:Features>
+ </vcloud:Configuration>
+ <vcloud:IsDeployed>false</vcloud:IsDeployed>
+ </vcloud:NetworkConfig>
+ </vcloud:NetworkConfigSection>
+ <vcloud:LeaseSettingsSection type="application/vnd.vmware.vcloud.leaseSettingsSection+xml" href="https://vcd.stratogen.net/api/v1.0/vAppTemplate/vappTemplate-f8ca27ba-c6ee-44bd-91a9-416f464cba80/leaseSettingsSection/" ovf:required="false">
+ <ovf:Info>Lease settings section</ovf:Info>
+ <vcloud:Link rel="edit" type="application/vnd.vmware.vcloud.leaseSettingsSection+xml" href="https://vcd.stratogen.net/api/v1.0/vAppTemplate/vappTemplate-f8ca27ba-c6ee-44bd-91a9-416f464cba80/leaseSettingsSection/"/>
+ <vcloud:StorageLeaseInSeconds>0</vcloud:StorageLeaseInSeconds>
+ </vcloud:LeaseSettingsSection>
+ <vcloud:CustomizationSection type="application/vnd.vmware.vcloud.customizationSection+xml" href="https://vcd.stratogen.net/api/v1.0/vAppTemplate/vappTemplate-f8ca27ba-c6ee-44bd-91a9-416f464cba80/customizationSection/" ovf:required="false">
+ <ovf:Info>VApp template customization section</ovf:Info>
+ <vcloud:CustomizeOnInstantiate>true</vcloud:CustomizeOnInstantiate>
+ </vcloud:CustomizationSection>
+</vcloud:VAppTemplate>
\ No newline at end of file
diff --git a/apis/vcloud/src/test/resources/vdc1.0-vcd15.xml b/apis/vcloud/src/test/resources/vdc1.0-vcd15.xml
new file mode 100644
index 0000000..d705891
--- /dev/null
+++ b/apis/vcloud/src/test/resources/vdc1.0-vcd15.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Vdc xmlns="http://www.vmware.com/vcloud/v1" status="1" name="orgVDC-jclouds-Tier1-PAYG" type="application/vnd.vmware.vcloud.vdc+xml" href="https://zone.myvcloud.com/api/v1.0/vdc/e9cd3387-ac57-4d27-a481-9bee75e0690f" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1 https://zone.myvcloud.com/api/v1.0/schema/master.xsd">
+ <Link rel="up" type="application/vnd.vmware.vcloud.org+xml" href="https://zone.myvcloud.com/api/v1.0/org/c076f90a-397a-49fa-89b8-b294c1599cd0"/>
+ <Link rel="add" type="application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml" href="https://zone.myvcloud.com/api/v1.0/vdc/e9cd3387-ac57-4d27-a481-9bee75e0690f/action/uploadVAppTemplate"/>
+ <Link rel="add" type="application/vnd.vmware.vcloud.media+xml" href="https://zone.myvcloud.com/api/v1.0/vdc/e9cd3387-ac57-4d27-a481-9bee75e0690f/media"/>
+ <Link rel="add" type="application/vnd.vmware.vcloud.instantiateVAppTemplateParams+xml" href="https://zone.myvcloud.com/api/v1.0/vdc/e9cd3387-ac57-4d27-a481-9bee75e0690f/action/instantiateVAppTemplate"/>
+ <Link rel="add" type="application/vnd.vmware.vcloud.cloneVAppParams+xml" href="https://zone.myvcloud.com/api/v1.0/vdc/e9cd3387-ac57-4d27-a481-9bee75e0690f/action/cloneVApp"/>
+ <Link rel="add" type="application/vnd.vmware.vcloud.cloneVAppTemplateParams+xml" href="https://zone.myvcloud.com/api/v1.0/vdc/e9cd3387-ac57-4d27-a481-9bee75e0690f/action/cloneVAppTemplate"/>
+ <Link rel="add" type="application/vnd.vmware.vcloud.cloneMediaParams+xml" href="https://zone.myvcloud.com/api/v1.0/vdc/e9cd3387-ac57-4d27-a481-9bee75e0690f/action/cloneMedia"/>
+ <Link rel="add" type="application/vnd.vmware.vcloud.captureVAppParams+xml" href="https://zone.myvcloud.com/api/v1.0/vdc/e9cd3387-ac57-4d27-a481-9bee75e0690f/action/captureVApp"/>
+ <Link rel="add" type="application/vnd.vmware.vcloud.composeVAppParams+xml" href="https://zone.myvcloud.com/api/v1.0/vdc/e9cd3387-ac57-4d27-a481-9bee75e0690f/action/composeVApp"/>
+ <Description>Pay As You go resources for organization jclouds </Description>
+ <AllocationModel>AllocationVApp</AllocationModel>
+ <StorageCapacity>
+ <Units>MB</Units>
+ <Allocated>0</Allocated>
+ <Limit>0</Limit>
+ <Used>14336</Used>
+ <Overhead>0</Overhead>
+ </StorageCapacity>
+ <ComputeCapacity>
+ <Cpu>
+ <Units>MHz</Units>
+ <Allocated>0</Allocated>
+ <Limit>0</Limit>
+ <Used>0</Used>
+ <Overhead>0</Overhead>
+ </Cpu>
+ <Memory>
+ <Units>MB</Units>
+ <Allocated>0</Allocated>
+ <Limit>0</Limit>
+ <Used>0</Used>
+ <Overhead>0</Overhead>
+ </Memory>
+ </ComputeCapacity>
+ <ResourceEntities>
+ <ResourceEntity type="application/vnd.vmware.vcloud.vAppTemplate+xml" name="UbuntuServer-x64-2GB" href="https://zone.myvcloud.com/api/v1.0/vAppTemplate/vappTemplate-51891b97-c5dd-47dc-a687-aabae354f728"/>
+ </ResourceEntities>
+ <AvailableNetworks>
+ <Network type="application/vnd.vmware.vcloud.network+xml" name="orgNet-jclouds-External" href="https://zone.myvcloud.com/api/v1.0/network/b466c0c5-8a5c-4335-b703-a2e2e6b5f3e1"/>
+ </AvailableNetworks>
+ <NicQuota>0</NicQuota>
+ <NetworkQuota>10</NetworkQuota>
+ <VmQuota>10</VmQuota>
+ <IsEnabled>true</IsEnabled>
+</Vdc>
\ No newline at end of file
diff --git a/apis/vcloud/src/test/resources/versions-vcd15.xml b/apis/vcloud/src/test/resources/versions-vcd15.xml
new file mode 100644
index 0000000..ed24d3a
--- /dev/null
+++ b/apis/vcloud/src/test/resources/versions-vcd15.xml
@@ -0,0 +1,906 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<SupportedVersions xmlns="http://www.vmware.com/vcloud/versions" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/versions https://zone.myvcloud.com/api/versions/schema/versions.xsd">
+ <VersionInfo>
+ <Version>1.0</Version>
+ <LoginUrl>https://zone.myvcloud.com/api/v1.0/login</LoginUrl>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.customizationSection+xml</MediaType>
+ <ComplexTypeName>CustomizationSectionType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.catalogItem+xml</MediaType>
+ <ComplexTypeName>CatalogItemType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.networkConnectionSection+xml</MediaType>
+ <ComplexTypeName>NetworkConnectionSectionType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.owner+xml</MediaType>
+ <ComplexTypeName>OwnerType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.licensingReportList+xml</MediaType>
+ <ComplexTypeName>LicensingReportListType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.group+xml</MediaType>
+ <ComplexTypeName>GroupType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vdc+xml</MediaType>
+ <ComplexTypeName>AdminVdcType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.licensingReport+xml</MediaType>
+ <ComplexTypeName>LicensingReportType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.importVmAsVAppTemplateParams+xml</MediaType>
+ <ComplexTypeName>ImportVmAsVAppTemplateParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmwVimServerReferences+xml</MediaType>
+ <ComplexTypeName>VMWVimServerReferencesType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.vm+xml</MediaType>
+ <ComplexTypeName>VmType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml</MediaType>
+ <ComplexTypeName>UploadVAppTemplateParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.composeVAppParams+xml</MediaType>
+ <ComplexTypeName>ComposeVAppParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.orgList+xml</MediaType>
+ <ComplexTypeName>OrgListType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.cloneMediaParams+xml</MediaType>
+ <ComplexTypeName>CloneMediaParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.vmPendingQuestion+xml</MediaType>
+ <ComplexTypeName>VmPendingQuestionType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmwHostReferences+xml</MediaType>
+ <ComplexTypeName>VMWHostReferencesType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.undeployVAppParams+xml</MediaType>
+ <ComplexTypeName>UndeployVAppParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.leaseSettingsSection+xml</MediaType>
+ <ComplexTypeName>LeaseSettingsSectionType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.network+xml</MediaType>
+ <ComplexTypeName>OrgNetworkType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.deployVAppParams+xml</MediaType>
+ <ComplexTypeName>DeployVAppParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.cloneVAppTemplateParams+xml</MediaType>
+ <ComplexTypeName>CloneVAppTemplateParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.media+xml</MediaType>
+ <ComplexTypeName>MediaType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmwprovidervdc+xml</MediaType>
+ <ComplexTypeName>VMWProviderVdcType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.vAppTemplate+xml</MediaType>
+ <ComplexTypeName>VAppTemplateType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.org+xml</MediaType>
+ <ComplexTypeName>OrgType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.vApp+xml</MediaType>
+ <ComplexTypeName>VAppType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.catalog+xml</MediaType>
+ <ComplexTypeName>CatalogType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmwNetworkPool+xml</MediaType>
+ <ComplexTypeName>VMWNetworkPoolType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.tasksList+xml</MediaType>
+ <ComplexTypeName>TasksListType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vdcReferences+xml</MediaType>
+ <ComplexTypeName>VdcReferencesType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.screenTicket+xml</MediaType>
+ <ComplexTypeName>ScreenTicketType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.prepareHostParams+xml</MediaType>
+ <ComplexTypeName>PrepareHostParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vcloud+xml</MediaType>
+ <ComplexTypeName>VCloudType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.publishCatalogParams+xml</MediaType>
+ <ComplexTypeName>PublishCatalogParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.networkConfigSection+xml</MediaType>
+ <ComplexTypeName>NetworkConfigSectionType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.resourcePoolList+xml</MediaType>
+ <ComplexTypeName>ResourcePoolListType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.right+xml</MediaType>
+ <ComplexTypeName>RightType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmwExtension+xml</MediaType>
+ <ComplexTypeName>VMWExtensionType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.importVmAsVAppParams+xml</MediaType>
+ <ComplexTypeName>ImportVmAsVAppParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmwvirtualcenter+xml</MediaType>
+ <ComplexTypeName>VimServerType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmsObjectRefsList+xml</MediaType>
+ <ComplexTypeName>VmObjectRefsListType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.controlAccess+xml</MediaType>
+ <ComplexTypeName>ControlAccessParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.vdc+xml</MediaType>
+ <ComplexTypeName>VdcType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.role+xml</MediaType>
+ <ComplexTypeName>RoleType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.cloneVAppParams+xml</MediaType>
+ <ComplexTypeName>CloneVAppParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.host+xml</MediaType>
+ <ComplexTypeName>HostType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.organization+xml</MediaType>
+ <ComplexTypeName>AdminOrgType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.providervdc+xml</MediaType>
+ <ComplexTypeName>ProviderVdcType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.user+xml</MediaType>
+ <ComplexTypeName>UserType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmwProviderVdcReferences+xml</MediaType>
+ <ComplexTypeName>VMWProviderVdcReferencesType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.mediaInsertOrEjectParams+xml</MediaType>
+ <ComplexTypeName>MediaInsertOrEjectParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.instantiateVAppTemplateParams+xml</MediaType>
+ <ComplexTypeName>InstantiateVAppTemplateParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.rasdItemsList+xml</MediaType>
+ <ComplexTypeName>RasdItemsListType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.task+xml</MediaType>
+ <ComplexTypeName>TaskType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmwNetworkPoolReferences+xml</MediaType>
+ <ComplexTypeName>VMWNetworkPoolReferencesType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.guestCustomizationSection+xml</MediaType>
+ <ComplexTypeName>GuestCustomizationSectionType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.recomposeVAppParams+xml</MediaType>
+ <ComplexTypeName>RecomposeVAppParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.importMediaParams+xml</MediaType>
+ <ComplexTypeName>ImportMediaParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmwExternalNetworkReferences+xml</MediaType>
+ <ComplexTypeName>VMWExternalNetworkReferencesType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmwexternalnet+xml</MediaType>
+ <ComplexTypeName>VMWExternalNetworkType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.captureVAppParams+xml</MediaType>
+ <ComplexTypeName>CaptureVAppParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.vmPendingAnswer+xml</MediaType>
+ <ComplexTypeName>VmQuestionAnswerType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.registerVimServerParams+xml</MediaType>
+ <ComplexTypeName>RegisterVimServerParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.rasdItem+xml</MediaType>
+ <ComplexTypeName>RASD_Type</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.0/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.startupSection+xml</MediaType>
+ <ComplexTypeName>StartupSection_Type</ComplexTypeName>
+ <SchemaLocation>http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.virtualHardwareSection+xml</MediaType>
+ <ComplexTypeName>VirtualHardwareSection_Type</ComplexTypeName>
+ <SchemaLocation>http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.operatingSystemSection+xml</MediaType>
+ <ComplexTypeName>OperatingSystemSection_Type</ComplexTypeName>
+ <SchemaLocation>http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.networkSection+xml</MediaType>
+ <ComplexTypeName>NetworkSection_Type</ComplexTypeName>
+ <SchemaLocation>http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ </VersionInfo>
+ <VersionInfo>
+ <Version>1.5</Version>
+ <LoginUrl>https://zone.myvcloud.com/api/sessions</LoginUrl>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.instantiateVAppTemplateParams+xml</MediaType>
+ <ComplexTypeName>InstantiateVAppTemplateParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmwProviderVdcReferences+xml</MediaType>
+ <ComplexTypeName>VMWProviderVdcReferencesType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.customizationSection+xml</MediaType>
+ <ComplexTypeName>CustomizationSectionType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.prepareHostParams+xml</MediaType>
+ <ComplexTypeName>PrepareHostParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.relocateVmParams+xml</MediaType>
+ <ComplexTypeName>RelocateParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.org+xml</MediaType>
+ <ComplexTypeName>OrgType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmwExternalNetworkReferences+xml</MediaType>
+ <ComplexTypeName>VMWExternalNetworkReferencesType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.networkConnectionSection+xml</MediaType>
+ <ComplexTypeName>NetworkConnectionSectionType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.host+xml</MediaType>
+ <ComplexTypeName>HostType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.catalogItem+xml</MediaType>
+ <ComplexTypeName>CatalogItemType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.owner+xml</MediaType>
+ <ComplexTypeName>OwnerType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.vdc+xml</MediaType>
+ <ComplexTypeName>VdcType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vdc+xml</MediaType>
+ <ComplexTypeName>AdminVdcType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.catalog+xml</MediaType>
+ <ComplexTypeName>AdminCatalogType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.recomposeVAppParams+xml</MediaType>
+ <ComplexTypeName>RecomposeVAppParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.importVmIntoExistingVAppParams+xml</MediaType>
+ <ComplexTypeName>ImportVmIntoExistingVAppParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.taskExtensionRequestUpdateProgressOperationParams+xml</MediaType>
+ <ComplexTypeName>TaskExtensionRequestUpdateProgressParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.catalog+xml</MediaType>
+ <ComplexTypeName>CatalogType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.cloneVAppTemplateParams+xml</MediaType>
+ <ComplexTypeName>CloneVAppTemplateParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.providervdc+xml</MediaType>
+ <ComplexTypeName>ProviderVdcType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmsObjectRefsList+xml</MediaType>
+ <ComplexTypeName>VmObjectRefsListType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.undeployVAppParams+xml</MediaType>
+ <ComplexTypeName>UndeployVAppParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vdcReferences+xml</MediaType>
+ <ComplexTypeName>VdcReferencesType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.systemPasswordPolicySettings+xml</MediaType>
+ <ComplexTypeName>SystemPasswordPolicySettingsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.vApp+xml</MediaType>
+ <ComplexTypeName>VAppType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.taskExtensionRequest+xml</MediaType>
+ <ComplexTypeName>TaskExtensionRequestType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vimServerNetworks+xml</MediaType>
+ <ComplexTypeName>VimObjectRefListType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmwprovidervdc+xml</MediaType>
+ <ComplexTypeName>VMWProviderVdcType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.orgSettings+xml</MediaType>
+ <ComplexTypeName>OrgSettingsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.captureVAppParams+xml</MediaType>
+ <ComplexTypeName>CaptureVAppParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.screenTicket+xml</MediaType>
+ <ComplexTypeName>ScreenTicketType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.runtimeInfoSection+xml</MediaType>
+ <ComplexTypeName>RuntimeInfoSectionType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.tasksList+xml</MediaType>
+ <ComplexTypeName>TasksListType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.amqpSettingsTest+xml</MediaType>
+ <ComplexTypeName>AmqpSettingsTestType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.extensionSettings+xml</MediaType>
+ <ComplexTypeName>TaskExtensionSettingsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.importVmAsVAppTemplateParams+xml</MediaType>
+ <ComplexTypeName>ImportVmAsVAppTemplateParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.organizationGeneralSettings+xml</MediaType>
+ <ComplexTypeName>OrgGeneralSettingsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.registerVimServerParams+xml</MediaType>
+ <ComplexTypeName>RegisterVimServerParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.network+xml</MediaType>
+ <ComplexTypeName>OrgNetworkType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml</MediaType>
+ <ComplexTypeName>UploadVAppTemplateParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.datastore+xml</MediaType>
+ <ComplexTypeName>DatastoreType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.metadata+xml</MediaType>
+ <ComplexTypeName>MetadataType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.licensingReportList+xml</MediaType>
+ <ComplexTypeName>LicensingReportListType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmwNetworkPool+xml</MediaType>
+ <ComplexTypeName>VMWNetworkPoolType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.systemSettings+xml</MediaType>
+ <ComplexTypeName>SystemSettingsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmwHostReferences+xml</MediaType>
+ <ComplexTypeName>VMWHostReferencesType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.taskExtensionRequestOperationParams+xml</MediaType>
+ <ComplexTypeName>TaskExtensionRequestOperationParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.metadata.value+xml</MediaType>
+ <ComplexTypeName>MetadataValueType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.taskOperationList+xml</MediaType>
+ <ComplexTypeName>TaskOperationListType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.media+xml</MediaType>
+ <ComplexTypeName>MediaType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.productSections+xml</MediaType>
+ <ComplexTypeName>ProductSectionListType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.amqpSettings+xml</MediaType>
+ <ComplexTypeName>AmqpSettingsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.vAppTemplate+xml</MediaType>
+ <ComplexTypeName>VAppTemplateType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.deployVAppParams+xml</MediaType>
+ <ComplexTypeName>DeployVAppParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.importVmIntoExistingVAppTemplateParams+xml</MediaType>
+ <ComplexTypeName>ImportVmIntoExistingVAppTemplateParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.resourcePoolList+xml</MediaType>
+ <ComplexTypeName>ResourcePoolListType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.networkConfigSection+xml</MediaType>
+ <ComplexTypeName>NetworkConfigSectionType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.OrganizationVdcResourcePoolSet+xml</MediaType>
+ <ComplexTypeName>OrganizationResourcePoolSetType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.organizationPasswordPolicySettings+xml</MediaType>
+ <ComplexTypeName>OrgPasswordPolicySettingsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.publishCatalogParams+xml</MediaType>
+ <ComplexTypeName>PublishCatalogParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmwExtension+xml</MediaType>
+ <ComplexTypeName>VMWExtensionType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.mediaInsertOrEjectParams+xml</MediaType>
+ <ComplexTypeName>MediaInsertOrEjectParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.vmPendingQuestion+xml</MediaType>
+ <ComplexTypeName>VmPendingQuestionType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.notificationsSettings+xml</MediaType>
+ <ComplexTypeName>NotificationsSettingsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.ldapUserSettings+xml</MediaType>
+ <ComplexTypeName>LdapUserAttributesType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.right+xml</MediaType>
+ <ComplexTypeName>RightType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.ldapSettings+xml</MediaType>
+ <ComplexTypeName>LdapSettingsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.organization+xml</MediaType>
+ <ComplexTypeName>AdminOrgType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.orgList+xml</MediaType>
+ <ComplexTypeName>OrgListType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vAppTemplateLeaseSettings+xml</MediaType>
+ <ComplexTypeName>OrgVAppTemplateLeaseSettingsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmwVimServerReferences+xml</MediaType>
+ <ComplexTypeName>VMWVimServerReferencesType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmwexternalnet+xml</MediaType>
+ <ComplexTypeName>VMWExternalNetworkType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.entity+xml</MediaType>
+ <ComplexTypeName>EntityType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.cloneMediaParams+xml</MediaType>
+ <ComplexTypeName>CloneMediaParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.licensingReport+xml</MediaType>
+ <ComplexTypeName>LicensingReportType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.importMediaParams+xml</MediaType>
+ <ComplexTypeName>ImportMediaParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.resourcePoolSetUpdateParams+xml</MediaType>
+ <ComplexTypeName>UpdateResourcePoolSetParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.taskExtensionRequestList+xml</MediaType>
+ <ComplexTypeName>ReferencesType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.vmPendingAnswer+xml</MediaType>
+ <ComplexTypeName>VmQuestionAnswerType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.rasdItemsList+xml</MediaType>
+ <ComplexTypeName>RasdItemsListType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.generalSettings+xml</MediaType>
+ <ComplexTypeName>GeneralSettingsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmwNetworkPoolReferences+xml</MediaType>
+ <ComplexTypeName>VMWNetworkPoolReferencesType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.group+xml</MediaType>
+ <ComplexTypeName>GroupType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.controlAccess+xml</MediaType>
+ <ComplexTypeName>ControlAccessParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.ldapGroupSettings+xml</MediaType>
+ <ComplexTypeName>LdapGroupAttributesType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.user+xml</MediaType>
+ <ComplexTypeName>UserType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vcloud+xml</MediaType>
+ <ComplexTypeName>VCloudType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.uberAdminSettings+xml</MediaType>
+ <ComplexTypeName>UberAdminSettingsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmwvirtualcenter+xml</MediaType>
+ <ComplexTypeName>VimServerType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.leaseSettingsSection+xml</MediaType>
+ <ComplexTypeName>LeaseSettingsSectionType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.composeVAppParams+xml</MediaType>
+ <ComplexTypeName>ComposeVAppParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.organizationEmailSettings+xml</MediaType>
+ <ComplexTypeName>OrgEmailSettingsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.vm+xml</MediaType>
+ <ComplexTypeName>VmType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmwProviderVdcResourcePoolSet+xml</MediaType>
+ <ComplexTypeName>VMWProviderVdcResourcePoolSetType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.cloneVAppParams+xml</MediaType>
+ <ComplexTypeName>CloneVAppParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.guestCustomizationSection+xml</MediaType>
+ <ComplexTypeName>GuestCustomizationSectionType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.task+xml</MediaType>
+ <ComplexTypeName>TaskType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.session+xml</MediaType>
+ <ComplexTypeName>SessionType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vAppLeaseSettings+xml</MediaType>
+ <ComplexTypeName>OrgLeaseSettingsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.importVmAsVAppParams+xml</MediaType>
+ <ComplexTypeName>ImportVmAsVAppParamsType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.role+xml</MediaType>
+ <ComplexTypeName>RoleType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.rasdItem+xml</MediaType>
+ <ComplexTypeName>RASD_Type</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.startupSection+xml</MediaType>
+ <ComplexTypeName>StartupSection_Type</ComplexTypeName>
+ <SchemaLocation>http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.virtualHardwareSection+xml</MediaType>
+ <ComplexTypeName>VirtualHardwareSection_Type</ComplexTypeName>
+ <SchemaLocation>http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.operatingSystemSection+xml</MediaType>
+ <ComplexTypeName>OperatingSystemSection_Type</ComplexTypeName>
+ <SchemaLocation>http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.networkSection+xml</MediaType>
+ <ComplexTypeName>NetworkSection_Type</ComplexTypeName>
+ <SchemaLocation>http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.vAppNetwork+xml</MediaType>
+ <ComplexTypeName>VAppNetworkType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.network+xml</MediaType>
+ <ComplexTypeName>NetworkType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.vcloud.orgNetwork+xml</MediaType>
+ <ComplexTypeName>OrgNetworkType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/master.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ <MediaTypeMapping>
+ <MediaType>application/vnd.vmware.admin.vmwexternalnet+xml</MediaType>
+ <ComplexTypeName>VMWExternalNetworkType</ComplexTypeName>
+ <SchemaLocation>https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd</SchemaLocation>
+ </MediaTypeMapping>
+ </VersionInfo>
+</SupportedVersions>
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/BlobStores.java b/blobstore/src/main/java/org/jclouds/blobstore/BlobStores.java
index fb3b418..b59d60f 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/BlobStores.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/BlobStores.java
@@ -22,22 +22,55 @@
import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata;
+import org.jclouds.blobstore.options.ListAllOptions;
import org.jclouds.blobstore.options.ListContainerOptions;
import com.google.common.annotations.Beta;
import com.google.common.collect.AbstractIterator;
+/**
+ * Utilities for using Blob Stores.
+ *
+ * @author Aled Sage
+ * @since 1.3
+ */
public class BlobStores {
/**
+ * @see listAll(BlobStore, String, ListContainerOptions, ListAllOptions)
+ */
+ @Beta
+ public static Iterable<StorageMetadata> listAll(BlobStore blobStore, String container,
+ ListContainerOptions containerOptions) {
+ return listAll(blobStore, container, containerOptions, ListAllOptions.NONE);
+ }
+
+ /**
* A variant of BlobStore.list(String, ListContainerOptions) that
* produces an Iterable over the entire set of results, not just one
* page, making multiple calls to BlobStore.list as needed.
+ *
+ * Note that if listAllOptions.isEager, then the first page will be fetched
+ * immediately and cached. Repeatedly iterating will not re-fetch (and thus
+ * will not refresh) the first page.
+ *
+ * @throws ContainerNotFoundException If listAllOptions.isEager and container cannot be found
*/
@Beta
public static Iterable<StorageMetadata> listAll(final BlobStore blobStore, final String container,
- final ListContainerOptions options) {
+ final ListContainerOptions containerOptions, final ListAllOptions listAllOptions) {
+ final boolean eager = listAllOptions.isEager();
+ final PageSet<? extends StorageMetadata> firstList;
+ final String firstMarker;
+ if (eager) {
+ firstList = blobStore.list(container, containerOptions);
+ firstMarker = firstList.getNextMarker();
+ } else {
+ firstList = null;
+ firstMarker = null;
+ }
+
return new Iterable<StorageMetadata>() {
public Iterator<StorageMetadata> iterator() {
return new AbstractIterator<StorageMetadata>() {
@@ -47,10 +80,16 @@
public StorageMetadata computeNext() {
while (true) {
if (iterator == null) {
- ListContainerOptions nextOptions = marker == null ? options : options.clone().afterMarker(marker);
- PageSet<? extends StorageMetadata> list = blobStore.list(container, nextOptions);
+ PageSet<? extends StorageMetadata> list;
+ if (eager && marker == null) {
+ list = firstList;
+ marker = firstMarker;
+ } else {
+ ListContainerOptions nextOptions = marker == null ? containerOptions : containerOptions.clone().afterMarker(marker);
+ list = blobStore.list(container, nextOptions);
+ marker = list.getNextMarker();
+ }
iterator = list.iterator();
- marker = list.getNextMarker();
}
if (iterator.hasNext()) {
return iterator.next();
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/options/ListAllOptions.java b/blobstore/src/main/java/org/jclouds/blobstore/options/ListAllOptions.java
new file mode 100644
index 0000000..bdc4352
--- /dev/null
+++ b/blobstore/src/main/java/org/jclouds/blobstore/options/ListAllOptions.java
@@ -0,0 +1,95 @@
+package org.jclouds.blobstore.options;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+
+/**
+ * Contains options supported by BlobStores.listAll.
+ *
+ * @see ListOptions for recommended usage patterns
+ *
+ * @author Aled Sage
+ * @since 1.3
+ */
+@Beta
+public class ListAllOptions implements Cloneable {
+
+ public static final ImmutableListAllOptions NONE = new ImmutableListAllOptions(new ListAllOptions());
+
+ private boolean eager = false;
+
+ public ListAllOptions() {
+ }
+
+ ListAllOptions(boolean eagerness) {
+ this.eager = eagerness;
+ }
+
+ public static class ImmutableListAllOptions extends ListAllOptions {
+ private final ListAllOptions delegate;
+
+ public ImmutableListAllOptions(ListAllOptions delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public boolean isEager() {
+ return delegate.isEager();
+ }
+
+ @Override
+ public ListAllOptions eager(boolean val) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public boolean isEager() {
+ return eager;
+ }
+
+ /**
+ * If eager, will connect to container immediately and fail-fast, rather than failing when
+ * first iterating over the list.
+ */
+ public ListAllOptions eager(boolean val) {
+ this.eager = val;
+ return this;
+ }
+
+ public static class Builder {
+ /**
+ * @see ListAllOptions#eager(boolean)
+ */
+ public static ListAllOptions eager(boolean eager) {
+ ListAllOptions options = new ListAllOptions();
+ return options.eager(eager);
+ }
+ }
+
+ @Override
+ public ListAllOptions clone() {
+ return new ListAllOptions(isEager());
+ }
+
+ @Override
+ public String toString() {
+ return "[eager=" + eager + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(eager);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ListAllOptions other = (ListAllOptions) obj;
+ return (eager == other.eager);
+ }
+}
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/options/PutOptions.java b/blobstore/src/main/java/org/jclouds/blobstore/options/PutOptions.java
index 20c5373..70adcb7 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/options/PutOptions.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/options/PutOptions.java
@@ -34,12 +34,12 @@
public static final ImmutablePutOptions NONE = new ImmutablePutOptions(new PutOptions());
- private boolean multipart;
+ private boolean multipart = false;
public PutOptions() {
}
- PutOptions(boolean multipart) {
+ public PutOptions(boolean multipart) {
this.multipart = multipart;
}
diff --git a/blobstore/src/test/java/org/jclouds/blobstore/BlobStoresTest.java b/blobstore/src/test/java/org/jclouds/blobstore/BlobStoresTest.java
index 9ea6d13..0d8c8bd 100644
--- a/blobstore/src/test/java/org/jclouds/blobstore/BlobStoresTest.java
+++ b/blobstore/src/test/java/org/jclouds/blobstore/BlobStoresTest.java
@@ -18,17 +18,18 @@
*/
package org.jclouds.blobstore;
-import static org.easymock.classextension.EasyMock.createMock;
+import static org.easymock.EasyMock.createMock;
import static org.testng.Assert.assertEquals;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
-import org.easymock.classextension.EasyMock;
+import org.easymock.EasyMock;
import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.domain.internal.PageSetImpl;
+import org.jclouds.blobstore.options.ListAllOptions;
import org.jclouds.blobstore.options.ListContainerOptions;
import org.testng.annotations.Test;
@@ -37,72 +38,105 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
+@Test(singleThreaded = true, testName = "BlobStoresTest")
public class BlobStoresTest {
private final String containerName = "mycontainer";
- @Test(expectedExceptions={ContainerNotFoundException.class})
+ @Test(expectedExceptions = { ContainerNotFoundException.class })
+ public void testListAllForUnknownContainerFromTransientBlobStoreEagerly() throws Exception {
+ ListContainerOptions containerOptions = ListContainerOptions.NONE;
+ ListAllOptions listAllOptions = ListAllOptions.Builder.eager(true);
+ BlobStoreContext context = new BlobStoreContextFactory().createContext("transient", "dummyid", "dummykey");
+ try {
+ BlobStore blobStore = context.getBlobStore();
+ BlobStores.listAll(blobStore, "wrongcontainer", containerOptions, listAllOptions);
+ } finally {
+ context.close();
+ }
+ }
+
+ /**
+ * Default listAll is not eager, so test that exception is thrown when first attempt to iterate.
+ */
+ @Test(expectedExceptions = { ContainerNotFoundException.class })
public void testListAllForUnknownContainerFromTransientBlobStore() throws Exception {
ListContainerOptions options = ListContainerOptions.NONE;
BlobStoreContext context = new BlobStoreContextFactory().createContext("transient", "dummyid", "dummykey");
try {
BlobStore blobStore = context.getBlobStore();
-
- // Arguably it would be best to throw the exception as soon as listAll is called; but because
- // the iterator is lazy we don't the exception until we first call iterator().next() or hasNext().
Iterable<StorageMetadata> iterable = BlobStores.listAll(blobStore, "wrongcontainer", options);
iterable.iterator().hasNext();
} finally {
context.close();
}
}
-
+
@Test
public void testListAllFromTransientBlobStore() throws Exception {
+ runListAllFromTransientBlobStore(false);
+ }
+
+ @Test
+ public void testListAllFromTransientBlobStoreEagerly() throws Exception {
+ runListAllFromTransientBlobStore(true);
+ }
+
+ private void runListAllFromTransientBlobStore(boolean eager) throws Exception {
+ final int numTimesToIterate = 2;
final int NUM_BLOBS = 31;
- ListContainerOptions options = ListContainerOptions.Builder.maxResults(10);
+ ListContainerOptions containerOptions = ListContainerOptions.Builder.maxResults(10);
BlobStoreContext context = new BlobStoreContextFactory().createContext("transient", "dummyid", "dummykey");
BlobStore blobStore = null;
try {
blobStore = context.getBlobStore();
- blobStore.createContainerInLocation(null, containerName);
+ blobStore.createContainerInLocation(null, containerName);
Set<String> expectedNames = new HashSet<String>();
for (int i = 0; i < NUM_BLOBS; i++) {
- String blobName = "myname"+i;
- blobStore.putBlob(containerName, blobStore.blobBuilder(blobName).payload("payload"+i).build());
+ String blobName = "myname" + i;
+ blobStore.putBlob(containerName, blobStore.blobBuilder(blobName).payload("payload" + i).build());
expectedNames.add(blobName);
}
-
- Iterable<StorageMetadata> iterable = BlobStores.listAll(blobStore, containerName, options);
- Iterable<String> iterableNames = Iterables.transform(iterable, new Function<StorageMetadata,String>() {
- @Override public String apply(StorageMetadata input) {
- return input.getName();
- }});
-
- // Note that blob.getMetadata being put does not equal blob metadata being retrieved
- // because uri is null in one and populated in the other.
- // Therefore we just compare names to ensure the iterator worked.
- assertEquals(ImmutableSet.copyOf(iterableNames), expectedNames);
+
+ ListAllOptions listAllOptions = ListAllOptions.Builder.eager(eager);
+ Iterable<StorageMetadata> iterable = BlobStores.listAll(blobStore, containerName, containerOptions,
+ listAllOptions);
+
+ for (int i = 0; i < numTimesToIterate; i++) {
+ Iterable<String> iterableNames = Iterables.transform(iterable, new Function<StorageMetadata, String>() {
+ @Override
+ public String apply(StorageMetadata input) {
+ return input.getName();
+ }
+ });
+
+ // Note that blob.getMetadata being put does not equal blob metadata being retrieved
+ // because uri is null in one and populated in the other.
+ // Therefore we just compare names to ensure the iterator worked.
+ assertEquals(ImmutableSet.copyOf(iterableNames), expectedNames);
+ }
} finally {
- if (blobStore != null) blobStore.deleteContainer(containerName);
+ if (blobStore != null)
+ blobStore.deleteContainer(containerName);
context.close();
}
}
-
+
@Test
public void testListAllWhenOnePage() throws Exception {
BlobStore blobStore = createMock(BlobStore.class);
ListContainerOptions options = ListContainerOptions.NONE;
StorageMetadata v1 = createMock(StorageMetadata.class);
PageSet<StorageMetadata> pageSet = new PageSetImpl<StorageMetadata>(Collections.singletonList(v1), null);
-
- EasyMock.<PageSet<? extends StorageMetadata>>expect(blobStore.list(containerName, options)).andReturn(pageSet).once();
+
+ EasyMock.<PageSet<? extends StorageMetadata>> expect(blobStore.list(containerName, options)).andReturn(pageSet)
+ .once();
EasyMock.replay(blobStore);
-
+
Iterable<StorageMetadata> iterable = BlobStores.listAll(blobStore, containerName, options);
assertEquals(ImmutableList.copyOf(iterable), ImmutableList.of(v1));
}
-
+
@Test
public void testListAllWhenTwoPages() throws Exception {
BlobStore blobStore = createMock(BlobStore.class);
@@ -112,11 +146,13 @@
StorageMetadata v2 = createMock(StorageMetadata.class);
PageSet<StorageMetadata> pageSet = new PageSetImpl<StorageMetadata>(Collections.singletonList(v1), "marker1");
PageSet<StorageMetadata> pageSet2 = new PageSetImpl<StorageMetadata>(Collections.singletonList(v2), null);
-
- EasyMock.<PageSet<? extends StorageMetadata>>expect(blobStore.list(containerName, options)).andReturn(pageSet).once();
- EasyMock.<PageSet<? extends StorageMetadata>>expect(blobStore.list(containerName, options2)).andReturn(pageSet2).once();
+
+ EasyMock.<PageSet<? extends StorageMetadata>> expect(blobStore.list(containerName, options)).andReturn(pageSet)
+ .once();
+ EasyMock.<PageSet<? extends StorageMetadata>> expect(blobStore.list(containerName, options2)).andReturn(pageSet2)
+ .once();
EasyMock.replay(blobStore);
-
+
Iterable<StorageMetadata> iterable = BlobStores.listAll(blobStore, containerName, options);
assertEquals(ImmutableList.copyOf(iterable), ImmutableList.of(v1, v2));
}
diff --git a/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobLiveTest.java b/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobLiveTest.java
index 0055e50..7bd700a 100644
--- a/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobLiveTest.java
+++ b/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobLiveTest.java
@@ -21,12 +21,12 @@
import static com.google.common.base.Preconditions.checkNotNull;
import static org.testng.Assert.assertEquals;
-import java.io.InputStream;
-import java.net.URL;
-import java.net.URLConnection;
+import java.net.URI;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.crypto.CryptoStreams;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
import org.testng.annotations.Optional;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
@@ -42,25 +42,24 @@
public class BaseBlobLiveTest extends BaseBlobStoreIntegrationTest {
private static final String sysHttpStreamUrl = System.getProperty("jclouds.blobstore.httpstream.url");
- private static final String sysHttpStreamETag = System.getProperty("jclouds.blobstore.httpstream.md5");
+ private static final String sysHttpStreamMD5 = System.getProperty("jclouds.blobstore.httpstream.md5");
@Test
- @Parameters({ "jclouds.blobstore.httpstream.url", "jclouds.blobstore.httpstream.md5" })
- public void testCopyUrl(@Optional String httpStreamUrl, @Optional String httpStreamETag) throws Exception {
+ @Parameters( { "jclouds.blobstore.httpstream.url", "jclouds.blobstore.httpstream.md5" })
+ public void testCopyUrl(@Optional String httpStreamUrl, @Optional String httpStreamMD5) throws Exception {
httpStreamUrl = checkNotNull(httpStreamUrl != null ? httpStreamUrl : sysHttpStreamUrl, "httpStreamUrl");
- httpStreamETag = checkNotNull(httpStreamETag != null ? httpStreamETag : sysHttpStreamETag, "httpStreamMd5");
+ httpStreamMD5 = checkNotNull(httpStreamMD5 != null ? httpStreamMD5 : sysHttpStreamMD5, "httpStreamMd5");
+
+ HttpResponse response = context.utils().http().invoke(
+ HttpRequest.builder().method("GET").endpoint(URI.create(httpStreamUrl)).build());
+ long length = response.getPayload().getContentMetadata().getContentLength();
String name = "hello";
+ byte[] md5 = CryptoStreams.hex(httpStreamMD5);
- URL url = new URL(httpStreamUrl);
- byte[] md5 = CryptoStreams.hex(httpStreamETag);
-
- URLConnection connection = url.openConnection();
- long length = connection.getContentLength();
- InputStream input = connection.getInputStream();
-
- Blob blob = context.getBlobStore().blobBuilder(name).payload(input).contentLength(length).contentMD5(md5).build();
+ Blob blob = context.getBlobStore().blobBuilder(name).payload(response.getPayload()).contentLength(length)
+ .contentMD5(md5).build();
String container = getContainerName();
try {
context.getBlobStore().putBlob(container, blob);
diff --git a/common/openstack/src/main/java/org/jclouds/openstack/config/OpenStackAuthenticationModule.java b/common/openstack/src/main/java/org/jclouds/openstack/config/OpenStackAuthenticationModule.java
index e7f180d..d2c8949 100644
--- a/common/openstack/src/main/java/org/jclouds/openstack/config/OpenStackAuthenticationModule.java
+++ b/common/openstack/src/main/java/org/jclouds/openstack/config/OpenStackAuthenticationModule.java
@@ -18,6 +18,9 @@
*/
package org.jclouds.openstack.config;
+import static com.google.common.base.Suppliers.memoizeWithExpiration;
+import static com.google.common.base.Throwables.propagate;
+
import java.util.Date;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@@ -29,23 +32,24 @@
import javax.inject.Singleton;
import org.jclouds.Constants;
-import org.jclouds.concurrent.RetryOnTimeOutExceptionSupplier;
+import org.jclouds.concurrent.RetryOnTimeOutExceptionFunction;
import org.jclouds.date.TimeStamp;
+import org.jclouds.domain.Credentials;
import org.jclouds.http.RequiresHttp;
+import org.jclouds.location.Provider;
import org.jclouds.openstack.Authentication;
import org.jclouds.openstack.OpenStackAuthAsyncClient;
import org.jclouds.openstack.OpenStackAuthAsyncClient.AuthenticationResponse;
import org.jclouds.rest.AsyncClientFactory;
+import com.google.common.base.Function;
import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.base.Throwables;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
-import com.google.common.util.concurrent.UncheckedExecutionException;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
+import com.google.inject.TypeLiteral;
/**
* Configures the Rackspace authentication service connection, including logging and http transport.
@@ -57,6 +61,8 @@
@Override
protected void configure() {
+ bind(new TypeLiteral<Function<Credentials, AuthenticationResponse>>() {
+ }).to(GetAuthenticationResponse.class);
}
/**
@@ -74,72 +80,60 @@
};
}
+ @Provides
+ @Provider
+ protected Credentials provideAuthenticationCredentials(@Named(Constants.PROPERTY_IDENTITY) String user,
+ @Named(Constants.PROPERTY_CREDENTIAL) String key) {
+ return new Credentials(user, key);
+ }
+
@Singleton
- public static class GetAuthenticationResponse implements Supplier<AuthenticationResponse> {
- protected final OpenStackAuthAsyncClient client;
- protected final String user;
- protected final String key;
+ public static class GetAuthenticationResponse extends
+ RetryOnTimeOutExceptionFunction<Credentials, AuthenticationResponse> {
@Inject
- public GetAuthenticationResponse(AsyncClientFactory factory, @Named(Constants.PROPERTY_IDENTITY) String user,
- @Named(Constants.PROPERTY_CREDENTIAL) String key) {
- this.client = factory.create(OpenStackAuthAsyncClient.class);
- this.user = user;
- this.key = key;
- }
+ public GetAuthenticationResponse(final AsyncClientFactory factory) {
+ super(new Function<Credentials, AuthenticationResponse>() {
- @Override
- public AuthenticationResponse get() {
- try {
- Future<AuthenticationResponse> response = authenticate();
- return response.get(30, TimeUnit.SECONDS);
- } catch (Exception e) {
- Throwables.propagate(e);
- assert false : e;
- return null;
- }
- }
+ @Override
+ public AuthenticationResponse apply(Credentials input) {
+ try {
+ Future<AuthenticationResponse> response = factory.create(OpenStackAuthAsyncClient.class)
+ .authenticate(input.identity, input.credential);
+ return response.get(30, TimeUnit.SECONDS);
+ } catch (Exception e) {
+ throw propagate(e);
+ }
+ }
- protected Future<AuthenticationResponse> authenticate() {
- return client.authenticate(user, key);
- }
+ @Override
+ public String toString() {
+ return "authenticate()";
+ }
+ });
+ }
}
@Provides
@Singleton
- public LoadingCache<String,AuthenticationResponse> provideAuthenticationResponseCache2(
- final GetAuthenticationResponse getAuthenticationResponse) {
-
- final RetryOnTimeOutExceptionSupplier<AuthenticationResponse> delegate =
- new RetryOnTimeOutExceptionSupplier<AuthenticationResponse>(getAuthenticationResponse);
-
- CacheLoader<String, AuthenticationResponse> cacheLoader = new CacheLoader<String, AuthenticationResponse>() {
- @Override
- public AuthenticationResponse load(String key) throws Exception {
- return delegate.get();
- }
- };
-
- LoadingCache<String, AuthenticationResponse> cache = CacheBuilder.newBuilder().expireAfterWrite(23, TimeUnit.HOURS)
- .build(cacheLoader);
-
- return cache;
+ public LoadingCache<Credentials, AuthenticationResponse> provideAuthenticationResponseCache2(
+ Function<Credentials, AuthenticationResponse> getAuthenticationResponse) {
+ return CacheBuilder.newBuilder().expireAfterWrite(23, TimeUnit.HOURS).build(
+ CacheLoader.from(getAuthenticationResponse));
}
@Provides
@Singleton
protected Supplier<AuthenticationResponse> provideAuthenticationResponseSupplier(
- final LoadingCache<String,AuthenticationResponse> cache) {
+ final LoadingCache<Credentials, AuthenticationResponse> cache, @Provider final Credentials creds) {
return new Supplier<AuthenticationResponse>() {
@Override
public AuthenticationResponse get() {
try {
- return cache.get("key");
- } catch (UncheckedExecutionException e) {
- throw Throwables.propagate(e.getCause());
+ return cache.get(creds);
} catch (ExecutionException e) {
- throw Throwables.propagate(e.getCause());
+ throw propagate(e.getCause());
}
}
};
@@ -149,7 +143,7 @@
@Singleton
@TimeStamp
protected Supplier<Date> provideCacheBusterDate() {
- return Suppliers.memoizeWithExpiration(new Supplier<Date>() {
+ return memoizeWithExpiration(new Supplier<Date>() {
public Date get() {
return new Date();
}
diff --git a/common/openstack/src/main/java/org/jclouds/openstack/handlers/RetryOnRenew.java b/common/openstack/src/main/java/org/jclouds/openstack/handlers/RetryOnRenew.java
index edb39e1..87d0739 100644
--- a/common/openstack/src/main/java/org/jclouds/openstack/handlers/RetryOnRenew.java
+++ b/common/openstack/src/main/java/org/jclouds/openstack/handlers/RetryOnRenew.java
@@ -18,19 +18,18 @@
*/
package org.jclouds.openstack.handlers;
+import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
import static org.jclouds.http.HttpUtils.releasePayload;
-import java.io.IOException;
-
import javax.annotation.Resource;
+import org.jclouds.domain.Credentials;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.logging.Logger;
import org.jclouds.openstack.OpenStackAuthAsyncClient.AuthenticationResponse;
import org.jclouds.openstack.reference.AuthHeaders;
-import org.jclouds.util.Strings2;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Multimap;
@@ -48,12 +47,12 @@
@Resource
protected Logger logger = Logger.NULL;
- // This doesn't work yet
-// @Inject
-// Supplier<AuthenticationResponse> providedAuthenticationResponseCache;
+ private final LoadingCache<Credentials, AuthenticationResponse> authenticationResponseCache;
@Inject
- LoadingCache<String,AuthenticationResponse> authenticationResponseCache;
+ protected RetryOnRenew(LoadingCache<Credentials, AuthenticationResponse> authenticationResponseCache) {
+ this.authenticationResponseCache = authenticationResponseCache;
+ }
@Override
public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
@@ -63,13 +62,13 @@
case 401:
// Do not retry on 401 from authentication request
Multimap<String, String> headers = command.getCurrentRequest().getHeaders();
- if (headers != null && headers.containsKey(AuthHeaders.AUTH_USER) && headers.containsKey(AuthHeaders.AUTH_KEY) &&
- !headers.containsKey(AuthHeaders.AUTH_TOKEN)) {
+ if (headers != null && headers.containsKey(AuthHeaders.AUTH_USER)
+ && headers.containsKey(AuthHeaders.AUTH_KEY) && !headers.containsKey(AuthHeaders.AUTH_TOKEN)) {
retry = false;
} else {
- String content = parsePayloadOrNull(response);
- if (content != null && content.contains("lease renew")) {
- // Otherwise invalidate the token cache, to force reauthentication
+ byte[] content = closeClientButKeepContentStream(response);
+ if (content != null && new String(content).contains("lease renew")) {
+ logger.debug("invalidating authentication token");
authenticationResponseCache.invalidateAll();
retry = true;
} else {
@@ -79,20 +78,10 @@
break;
}
return retry;
-
+
} finally {
releasePayload(response);
}
}
-
- String parsePayloadOrNull(HttpResponse response) {
- if (response.getPayload() != null) {
- try {
- return Strings2.toStringAndClose(response.getPayload().getInput());
- } catch (IOException e) {
- logger.warn(e, "exception reading error from response", response);
- }
- }
- return null;
- }
+
}
diff --git a/common/openstack/src/test/java/org/jclouds/openstack/handlers/RetryOnRenewTest.java b/common/openstack/src/test/java/org/jclouds/openstack/handlers/RetryOnRenewTest.java
index 0aa578f..36a6c3a 100644
--- a/common/openstack/src/test/java/org/jclouds/openstack/handlers/RetryOnRenewTest.java
+++ b/common/openstack/src/test/java/org/jclouds/openstack/handlers/RetryOnRenewTest.java
@@ -18,13 +18,14 @@
*/
package org.jclouds.openstack.handlers;
+import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
-import static org.easymock.classextension.EasyMock.createMock;
-import static org.easymock.classextension.EasyMock.replay;
-import static org.easymock.classextension.EasyMock.verify;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
import static org.testng.Assert.assertTrue;
+import org.jclouds.domain.Credentials;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
@@ -47,23 +48,22 @@
HttpRequest request = createMock(HttpRequest.class);
HttpResponse response = createMock(HttpResponse.class);
@SuppressWarnings("unchecked")
- LoadingCache<String,AuthenticationResponse> cache = createMock(LoadingCache.class);
+ LoadingCache<Credentials, AuthenticationResponse> cache = createMock(LoadingCache.class);
expect(command.getCurrentRequest()).andReturn(request);
cache.invalidateAll();
expectLastCall();
-
+
expect(response.getPayload()).andReturn(Payloads.newStringPayload("token expired, please renew")).anyTimes();
expect(response.getStatusCode()).andReturn(401).atLeastOnce();
replay(command);
replay(response);
replay(cache);
-
- RetryOnRenew retry = new RetryOnRenew();
- retry.authenticationResponseCache = cache;
-
+
+ RetryOnRenew retry = new RetryOnRenew(cache);
+
assertTrue(retry.shouldRetryRequest(command, response));
verify(command);
diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/TerremarkVCloudPropertiesBuilder.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/TerremarkVCloudPropertiesBuilder.java
index 5b6e9e6..a3081f8 100644
--- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/TerremarkVCloudPropertiesBuilder.java
+++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/TerremarkVCloudPropertiesBuilder.java
@@ -30,6 +30,7 @@
import static org.jclouds.trmk.vcloud_0_8.reference.VCloudConstants.PROPERTY_VCLOUD_XML_SCHEMA;
import java.util.Properties;
+import java.util.concurrent.TimeUnit;
import org.jclouds.PropertiesBuilder;
import org.jclouds.trmk.vcloud_0_8.domain.FenceMode;
@@ -49,8 +50,8 @@
properties.setProperty(PROPERTY_VCLOUD_XML_SCHEMA, "http://vcloud.safesecureweb.com/ns/vcloud.xsd");
properties.setProperty("jclouds.dns_name_length_min", "1");
properties.setProperty("jclouds.dns_name_length_max", "15");
- // with ssh key injection comes another reboot. allowing more time
- properties.setProperty(PROPERTY_VCLOUD_TIMEOUT_TASK_COMPLETED, 420l * 1000l + "");
+ // terremark can sometimes block extremely long times
+ properties.setProperty(PROPERTY_VCLOUD_TIMEOUT_TASK_COMPLETED, TimeUnit.MINUTES.toMillis(20) + "");
return properties;
}
diff --git a/compute/src/main/clojure/org/jclouds/compute2.clj b/compute/src/main/clojure/org/jclouds/compute2.clj
index 09489ed..bb02907 100644
--- a/compute/src/main/clojure/org/jclouds/compute2.clj
+++ b/compute/src/main/clojure/org/jclouds/compute2.clj
@@ -325,10 +325,12 @@
kw-memfn-0arg [:smallest :fastest :biggest :any])
(make-option-map
kw-memfn-1arg
- [:os-family :location-id :architecture :image-id :hardware-id
- :os-name-matches :os-version-matches :os-description-matches
- :os-64-bit :image-version-matches :image-name-matches
- :image-description-matches :min-cores :min-ram])))
+ [:from-hardware :from-image :from-template
+ :os-family :location-id :image-id :hardware-id
+ :os-name-matches :os-description-matches :os-version-matches
+ :os-arch-matches :os-64-bit :image-name-matches
+ :image-version-matches :image-description-matches :image-matches
+ :min-cores :min-ram])))
(def
^{:doc "TemplateOptions functions" :private true}
@@ -336,23 +338,56 @@
(merge
(make-option-map
kw-memfn-0arg
- [:destroy-on-error :enable-monitoring :no-placement-group :no-key-pair
- :with-details])
+ [;; ec2 trmk-ecloud trmk-vcloudexpress
+ :no-key-pair
+ ;; aws-ec2
+ :enable-monitoring :no-placement-group])
(make-option-map
kw-memfn-1arg
- [:run-script :install-private-key :authorize-public-key
- :override-credentials-with :override-login-user-with
- :override-login-credential-with
- ;; aws ec2 options
- :spot-price :spot-options :placement-group :subnet-id
- :block-device-mappings :unmapDeviceNamed :security-groups
- :key-pair :user-data])
- (make-option-map kw-memfn-varargs [:inbound-ports])
+ [;; RunScriptOptions
+ ;; deprecated
+ :override-credentials-with
+ :override-login-credentials
+ ;; deprecated
+ :override-login-user-with
+ :override-login-user
+ ;; deprecated
+ :override-login-credential-with
+ :override-login-password :override-login-privateKey
+ :override-authenticate-sudo
+
+ :name-task :run-as-root :wrap-in-init-script :block-on-complete
+ :block-on-port
+ ;; TemplateOptions
+ :run-script :install-private-key :authorize-public-key :tags
+ ;; cloudstack
+ :security-group-id :network-id :network-ids :setup-static-nat
+ :ip-on-default-network :ips-to-networks
+ ;; ec2
+ :security-groups :user-data :block-device-mappings
+ :unmap-device-named
+ ;; cloudstack ec2
+ :key-pair
+ ;; aws-ec2
+ :placement-group :subnet-id :spot-price :spot-options
+ ;; cloudstack aws-ec2
+ :security-group-ids
+ ;; softlayer
+ :domain-name
+ ;; trmk-ecloud trmk-vcloudexpress
+ :ssh-key-fingerprint
+ ;; vcloud
+ :description :customization-script :ip-address-allocation-mode])
+ (make-option-map
+ kw-memfn-varargs
+ [;; from TemplateOptions
+ :inbound-ports])
(make-option-map
kw-memfn-2arg
- [:block-on-port
- ;; aws ec2 options
- :map-ephemeral-device-to-device-name])
+ [;; from TemplateOptions
+ :block-on-port
+ ;; ec2 options
+ :map-ephemeral-device-to-device-name])
{:map-ebs-snapshot-to-device-name
(kw-memfn-apply :map-ebs-snapshot-to-device-name
device-name snapshot-id size-in-gib delete-on-termination)
@@ -384,17 +419,17 @@
The :os-family key expects a keyword version of OsFamily,
eg. :os-family :ubuntu.
-The :smallest, :fastest, :biggest, :any, and :destroy-on-error keys expect a
+The :smallest, :fastest, :biggest, and :any keys expect a
boolean value.
Options correspond to TemplateBuilder methods."
[#^ComputeService compute
- {:keys [os-family location-id architecture image-id hardware-id
- os-name-matches os-version-matches os-description-matches
- os-64-bit image-version-matches image-name-matches
- image-description-matches min-cores min-ram
- run-script install-private-key authorize-public-key
- inbound-ports smallest fastest biggest any destroy-on-error]
+ {:keys [from-hardware from-image from-template
+ os-family location-id image-id hardware-id
+ os-name-matches os-description-matches os-version-matches
+ os-arch-matches os-64-bit mage-name-matches
+ image-version-matches image-description-matches image-matches
+ min-cores min-ram smallest fastest biggest any]
:as options}]
(let [builder (.. compute (templateBuilder))]
(doseq [[option value] options]
diff --git a/compute/src/main/java/org/jclouds/compute/ComputeServiceAdapter.java b/compute/src/main/java/org/jclouds/compute/ComputeServiceAdapter.java
index 4101128..a9fa7e7 100644
--- a/compute/src/main/java/org/jclouds/compute/ComputeServiceAdapter.java
+++ b/compute/src/main/java/org/jclouds/compute/ComputeServiceAdapter.java
@@ -58,7 +58,7 @@
* includes {@code imageId}, {@code locationId}, and
* {@code hardwareId} used to resume the instance.
* @return library-native representation of a node.
- *
+ * TODO: return typed exception on createNodeFailure
* @see ComputeService#createNodesInGroup(String, int, Template)
*/
NodeAndInitialCredentials<N> createNodeWithGroupEncodedIntoName(String tag, String name, Template template);
diff --git a/compute/src/main/java/org/jclouds/compute/RunNodesException.java b/compute/src/main/java/org/jclouds/compute/RunNodesException.java
index 6c809ad..d6e73d1 100644
--- a/compute/src/main/java/org/jclouds/compute/RunNodesException.java
+++ b/compute/src/main/java/org/jclouds/compute/RunNodesException.java
@@ -35,26 +35,26 @@
/** The serialVersionUID */
private static final long serialVersionUID = -2272965726680821281L;
- private final String tag;
+ private final String group;
private final int count;
private final Template template;
private final Set<? extends NodeMetadata> successfulNodes;
private final Map<? extends NodeMetadata, ? extends Throwable> failedNodes;
private final Map<?, Exception> executionExceptions;
- public RunNodesException(String tag, int count, Template template,
+ public RunNodesException(String group, int count, Template template,
Set<? extends NodeMetadata> successfulNodes, Map<?, Exception> executionExceptions,
Map<? extends NodeMetadata, ? extends Throwable> failedNodes) {
super(
String
.format(
- "error running %d node%s tag(%s) location(%s) image(%s) size(%s) options(%s)%n%s%n%s",
- count, count > 1 ? "s" : "", tag, template.getLocation().getId(),
+ "error running %d node%s group(%s) location(%s) image(%s) size(%s) options(%s)%n%s%n%s",
+ count, count > 1 ? "s" : "", group, template.getLocation().getId(),
template.getImage().getProviderId(), template.getHardware()
.getProviderId(), template.getOptions(),
createExecutionErrorMessage(executionExceptions),
createNodeErrorMessage(failedNodes)));
- this.tag = tag;
+ this.group = group;
this.count = count;
this.template = template;
this.successfulNodes = successfulNodes;
@@ -86,8 +86,8 @@
return failedNodes;
}
- public String getTag() {
- return tag;
+ public String getGroup() {
+ return group;
}
public int getCount() {
diff --git a/compute/src/main/java/org/jclouds/compute/config/ComputeServiceAdapterContextModule.java b/compute/src/main/java/org/jclouds/compute/config/ComputeServiceAdapterContextModule.java
index a225389..8321e09 100644
--- a/compute/src/main/java/org/jclouds/compute/config/ComputeServiceAdapterContextModule.java
+++ b/compute/src/main/java/org/jclouds/compute/config/ComputeServiceAdapterContextModule.java
@@ -18,6 +18,11 @@
*/
package org.jclouds.compute.config;
+import static com.google.common.base.Functions.compose;
+import static com.google.common.base.Predicates.notNull;
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.transform;
+import static com.google.inject.util.Types.newParameterizedType;
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
import java.util.Set;
@@ -48,14 +53,11 @@
import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier;
import com.google.common.base.Function;
-import com.google.common.base.Functions;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
import com.google.inject.Provides;
import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
-import com.google.inject.util.Types;
/**
*
@@ -77,8 +79,8 @@
super.configure();
bind(new TypeLiteral<ComputeServiceContext>() {
}).to(
- (TypeLiteral) TypeLiteral.get(Types.newParameterizedType(ComputeServiceContextImpl.class,
- syncClientType, asyncClientType))).in(Scopes.SINGLETON);
+ (TypeLiteral) TypeLiteral.get(newParameterizedType(ComputeServiceContextImpl.class, syncClientType,
+ asyncClientType))).in(Scopes.SINGLETON);
}
@Override
@@ -95,7 +97,8 @@
seconds, new Supplier<Set<? extends Location>>() {
@Override
public Set<? extends Location> get() {
- return ImmutableSet.<Location> copyOf(Iterables.transform(adapter.listLocations(), transformer));
+ return ImmutableSet.<Location> copyOf(transform(filter(adapter.listLocations(), notNull()),
+ transformer));
}
});
}
@@ -108,7 +111,7 @@
@Override
public Iterable<H> get() {
- return adapter.listHardwareProfiles();
+ return filter(adapter.listHardwareProfiles(), notNull());
}
}, transformer);
@@ -122,10 +125,10 @@
@Override
public Iterable<I> get() {
- return adapter.listImages();
+ return filter(adapter.listImages(), notNull());
}
- }, Functions.compose(addDefaultCredentialsToImage, transformer));
+ }, compose(addDefaultCredentialsToImage, transformer));
}
@Singleton
@@ -139,6 +142,8 @@
@Override
public Image apply(Image arg0) {
+ if (arg0 == null)
+ return null;
LoginCredentials credentials = credsForImage.apply(arg0);
return credentials != null ? ImageBuilder.fromImage(arg0).defaultCredentials(credentials).build() : arg0;
}
diff --git a/compute/src/main/java/org/jclouds/compute/domain/CIMOperatingSystem.java b/compute/src/main/java/org/jclouds/compute/domain/CIMOperatingSystem.java
index 51c2503..54b9936 100644
--- a/compute/src/main/java/org/jclouds/compute/domain/CIMOperatingSystem.java
+++ b/compute/src/main/java/org/jclouds/compute/domain/CIMOperatingSystem.java
@@ -177,7 +177,7 @@
@Override
public String toString() {
- return String.format("[osType=%s, arch=%s, description=%s, family=%s, is64Bit=%s, name=%s, version=%s]", osType,
- arch, description, family, is64Bit, name, version);
+ return "[name=" + name + ", family=" + family + ", version=" + version + ", arch=" + arch + ", is64Bit="
+ + is64Bit + ", description=" + description + ", osType=" + osType+ "]";
}
}
\ No newline at end of file
diff --git a/compute/src/main/java/org/jclouds/compute/domain/OperatingSystem.java b/compute/src/main/java/org/jclouds/compute/domain/OperatingSystem.java
index a5a0254..8135675 100644
--- a/compute/src/main/java/org/jclouds/compute/domain/OperatingSystem.java
+++ b/compute/src/main/java/org/jclouds/compute/domain/OperatingSystem.java
@@ -211,7 +211,7 @@
return true;
if (obj == null)
return false;
- if (getClass() != obj.getClass())
+ if (!(obj instanceof OperatingSystem))
return false;
OperatingSystem other = (OperatingSystem) obj;
if (arch == null) {
diff --git a/compute/src/main/java/org/jclouds/compute/domain/internal/TemplateBuilderImpl.java b/compute/src/main/java/org/jclouds/compute/domain/internal/TemplateBuilderImpl.java
index 44d857c..6c3e0f3 100644
--- a/compute/src/main/java/org/jclouds/compute/domain/internal/TemplateBuilderImpl.java
+++ b/compute/src/main/java/org/jclouds/compute/domain/internal/TemplateBuilderImpl.java
@@ -25,10 +25,11 @@
import static com.google.common.collect.Iterables.size;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Lists.newArrayList;
+import static java.lang.String.format;
import static org.jclouds.compute.util.ComputeServiceUtils.getCores;
import static org.jclouds.compute.util.ComputeServiceUtils.getCoresAndSpeed;
import static org.jclouds.compute.util.ComputeServiceUtils.getSpace;
-import static java.lang.String.format;
+
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
@@ -59,6 +60,7 @@
import com.google.common.base.Supplier;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Ordering;
import com.google.common.primitives.Doubles;
@@ -67,7 +69,6 @@
*
* @author Adrian Cole
*/
-@SuppressWarnings("unchecked")
public class TemplateBuilderImpl implements TemplateBuilder {
@Resource
@@ -138,7 +139,7 @@
*
* If the input location is a parent of the specified location, then we are ok.
*/
- private final Predicate<ComputeMetadata> locationPredicate = new Predicate<ComputeMetadata>() {
+ final Predicate<ComputeMetadata> locationPredicate = new Predicate<ComputeMetadata>() {
@Override
public boolean apply(ComputeMetadata input) {
boolean returnVal = true;
@@ -314,7 +315,8 @@
if (input.getName() == null)
returnVal = false;
else
- returnVal = input.getName().contains(imageName) || input.getName().matches(imageName);
+ returnVal = input.getName().equals(imageName) || input.getName().contains(imageName)
+ || input.getName().matches(imageName);
}
return returnVal;
}
@@ -324,6 +326,7 @@
return "imageName(" + imageName + ")";
}
};
+
private final Predicate<Image> imageDescriptionPredicate = new Predicate<Image>() {
@Override
public boolean apply(Image input) {
@@ -350,10 +353,6 @@
boolean returnVal = true;
if (hardwareId != null) {
returnVal = hardwareId.equals(input.getId());
- // match our input params so that the later predicates pass.
- if (returnVal) {
- fromHardware(input);
- }
}
return returnVal;
}
@@ -388,9 +387,36 @@
return "minRam(" + minRam + ")";
}
};
- private final Predicate<Hardware> hardwarePredicate = and(hardwareIdPredicate, locationPredicate,
- hardwareCoresPredicate, hardwareRamPredicate);
+ private Predicate<Hardware> buildHardwarePredicate() {
+ List<Predicate<Hardware>> predicates = newArrayList();
+ if (hardwareId != null) {
+ predicates.add(hardwareIdPredicate);
+ } else {
+ if (location != null)
+ predicates.add(new Predicate<Hardware>() {
+
+ @Override
+ public boolean apply(Hardware input) {
+ return locationPredicate.apply(input);
+ }
+
+ @Override
+ public String toString() {
+ return locationPredicate.toString();
+ }
+ });
+ predicates.add(hardwareCoresPredicate);
+ predicates.add(hardwareRamPredicate);
+ }
+
+ // looks verbose, but explicit <Hardware> type needed for this to compile
+ // properly
+ Predicate<Hardware> hardwarePredicate = predicates.size() == 1 ? Iterables.<Predicate<Hardware>> get(predicates, 0)
+ : Predicates.<Hardware> and(predicates);
+ return hardwarePredicate;
+ }
+
static final Ordering<Hardware> DEFAULT_SIZE_ORDERING = new Ordering<Hardware>() {
public int compare(Hardware left, Hardware right) {
return ComparisonChain.start().compare(getCores(left), getCores(right)).compare(left.getRam(), right.getRam())
@@ -407,13 +433,15 @@
return ComparisonChain.start()
.compare(left.getName(), right.getName(), Ordering.<String> natural().nullsLast())
.compare(left.getVersion(), right.getVersion(), Ordering.<String> natural().nullsLast())
+ .compare(left.getDescription(), right.getDescription(), Ordering.<String> natural().nullsLast())
.compare(left.getOperatingSystem().getName(), right.getOperatingSystem().getName(),//
Ordering.<String> natural().nullsLast())
.compare(left.getOperatingSystem().getVersion(), right.getOperatingSystem().getVersion(),//
Ordering.<String> natural().nullsLast())
.compare(left.getOperatingSystem().getDescription(), right.getOperatingSystem().getDescription(),//
Ordering.<String> natural().nullsLast())
- .compare(left.getOperatingSystem().getArch(), right.getOperatingSystem().getArch()).result();
+ .compare(left.getOperatingSystem().getArch(), right.getOperatingSystem().getArch(),//
+ Ordering.<String> natural().nullsLast()).result();
}
};
@@ -543,6 +571,15 @@
};
+
+ private static final Function<Hardware, String> hardwareToId = new Function<Hardware, String>() {
+
+ @Override
+ public String apply(Hardware arg0) {
+ return arg0.getId();
+ }
+
+ };
/**
* {@inheritDoc}
*/
@@ -554,12 +591,14 @@
defaultTemplate.options(options);
return defaultTemplate.build();
}
- if (location == null)
- location = defaultLocation.get();
+
if (options == null)
options = optionsProvider.get();
logger.debug(">> searching params(%s)", this);
Set<? extends Image> images = getImages();
+ if (location == null)
+ location = defaultLocation.get();
+
Predicate<Image> imagePredicate = buildImagePredicate();
Iterable<? extends Image> supportedImages = filter(images, buildImagePredicate());
if (size(supportedImages) == 0) {
@@ -570,10 +609,10 @@
images);
}
}
- Hardware hardware = resolveSize(hardwareSorter(), supportedImages);
+
+ Hardware hardware = resolveHardware(hardwareSorter(), supportedImages);
Image image = resolveImage(hardware, supportedImages);
logger.debug("<< matched image(%s)", image.getId());
-
return new TemplateImpl(image, hardware, location, options);
}
@@ -584,36 +623,50 @@
throw exception;
}
- protected Hardware resolveSize(Ordering<Hardware> hardwareOrdering, final Iterable<? extends Image> images) {
+ protected Hardware resolveHardware(Ordering<Hardware> hardwareOrdering, final Iterable<? extends Image> images) {
Set<? extends Hardware> hardwarel = hardwares.get();
+ Iterable<? extends Hardware> hardwaresThatAreCompatibleWithOurImages = ImmutableSet.of();
+ try {
+ hardwaresThatAreCompatibleWithOurImages = filter(hardwarel, new Predicate<Hardware>() {
+ @Override
+ public boolean apply(final Hardware hardware) {
+ return Iterables.any(images, new Predicate<Image>() {
+
+ @Override
+ public boolean apply(Image input) {
+ return hardware.supportsImage().apply(input);
+ }
+
+ @Override
+ public String toString() {
+ return "hardware(" + hardware + ").supportsImage()";
+ }
+
+ });
+
+ }
+ });
+ } catch (NoSuchElementException exception) {
+
+ }
+ if (size(hardwaresThatAreCompatibleWithOurImages) == 0) {
+ String message = format("no hardware profiles support images matching params: %s", toString());
+ NoSuchElementException exception = new NoSuchElementException(message);
+ if (logger.isTraceEnabled())
+ logger.warn(exception, "hardware profiles %s\nimage ids %s", transform(hardwarel, hardwareToId), transform(
+ images, imageToId));
+ throw exception;
+ }
+ Predicate<Hardware> hardwarePredicate = buildHardwarePredicate();
Hardware hardware;
try {
- Iterable<? extends Hardware> hardwaresThatAreCompatibleWithOurImages = filter(hardwarel,
- new Predicate<Hardware>() {
- @Override
- public boolean apply(final Hardware hardware) {
- return Iterables.any(images, new Predicate<Image>() {
-
- @Override
- public boolean apply(Image input) {
- return hardware.supportsImage().apply(input);
- }
-
- @Override
- public String toString() {
- return "hardware(" + hardware + ").supportsImage()";
- }
-
- });
-
- }
- });
hardware = hardwareOrdering.max(filter(hardwaresThatAreCompatibleWithOurImages, hardwarePredicate));
} catch (NoSuchElementException exception) {
- String message = format("no hardware profiles support images matching params: %s", toString());
+ String message = format("no hardware profiles match params: %s", hardwarePredicate);
exception = new NoSuchElementException(message);
if (logger.isTraceEnabled())
- logger.warn(exception, "hardware profiles %s\nimage ids %s", hardwarel, transform(images, imageToId));
+ logger.warn(exception, "hardware profiles %s", transform(hardwaresThatAreCompatibleWithOurImages,
+ hardwareToId));
throw exception;
}
logger.debug("<< matched hardware(%s)", hardware.getId());
@@ -649,6 +702,7 @@
return "hardware(" + hardware + ").supportsImage()";
}
};
+
try {
Iterable<? extends Image> matchingImages = filter(supportedImages, imagePredicate);
if (logger.isTraceEnabled())
diff --git a/compute/src/main/java/org/jclouds/compute/strategy/impl/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java b/compute/src/main/java/org/jclouds/compute/strategy/impl/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java
index 9001074..a1f1a80 100644
--- a/compute/src/main/java/org/jclouds/compute/strategy/impl/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java
+++ b/compute/src/main/java/org/jclouds/compute/strategy/impl/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java
@@ -62,12 +62,12 @@
private class AddNode implements Callable<NodeMetadata> {
private final String name;
- private final String tag;
+ private final String group;
private final Template template;
- private AddNode(String name, String tag, Template template) {
+ private AddNode(String name, String group, Template template) {
this.name = checkNotNull(name, "name");
- this.tag = checkNotNull(tag, "tag");
+ this.group = checkNotNull(group, "group");
this.template = checkNotNull(template, "template");
}
@@ -77,13 +77,13 @@
logger.debug(">> adding node location(%s) name(%s) image(%s) hardware(%s)",
template.getLocation().getId(), name, template.getImage().getProviderId(), template.getHardware()
.getProviderId());
- node = addNodeWithTagStrategy.createNodeWithGroupEncodedIntoName(tag, name, template);
+ node = addNodeWithGroupStrategy.createNodeWithGroupEncodedIntoName(group, name, template);
logger.debug("<< %s node(%s)", node.getState(), node.getId());
return node;
}
public String toString() {
- return toStringHelper(this).add("name", name).add("tag", tag).add("template", template).toString();
+ return toStringHelper(this).add("name", name).add("group", group).add("template", template).toString();
}
}
@@ -91,7 +91,7 @@
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
- protected final CreateNodeWithGroupEncodedIntoName addNodeWithTagStrategy;
+ protected final CreateNodeWithGroupEncodedIntoName addNodeWithGroupStrategy;
protected final ListNodesStrategy listNodesStrategy;
protected final String nodeNamingConvention;
protected final ExecutorService executor;
@@ -99,12 +99,12 @@
@Inject
protected CreateNodesWithGroupEncodedIntoNameThenAddToSet(
- CreateNodeWithGroupEncodedIntoName addNodeWithTagStrategy,
+ CreateNodeWithGroupEncodedIntoName addNodeWithGroupStrategy,
ListNodesStrategy listNodesStrategy,
@Named("NAMING_CONVENTION") String nodeNamingConvention,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor,
CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory) {
- this.addNodeWithTagStrategy = addNodeWithTagStrategy;
+ this.addNodeWithGroupStrategy = addNodeWithGroupStrategy;
this.listNodesStrategy = listNodesStrategy;
this.nodeNamingConvention = nodeNamingConvention;
this.executor = executor;
@@ -112,15 +112,15 @@
}
/**
- * This implementation gets a list of acceptable node names to encode the tag into, then it
+ * This implementation gets a list of acceptable node names to encode the group into, then it
* simultaneously runs the nodes and applies options to them.
*/
@Override
- public Map<?, Future<Void>> execute(String tag, int count, Template template, Set<NodeMetadata> goodNodes,
+ public Map<?, Future<Void>> execute(String group, int count, Template template, Set<NodeMetadata> goodNodes,
Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
Map<String, Future<Void>> responses = newLinkedHashMap();
- for (String name : getNextNames(tag, template, count)) {
- responses.put(name, compose(executor.submit(new AddNode(name, tag, template)),
+ for (String name : getNextNames(group, template, count)) {
+ responses.put(name, compose(executor.submit(new AddNode(name, group, template)),
customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory.create(template.getOptions(),
goodNodes, badNodes, customizationResponses), executor));
}
@@ -128,22 +128,22 @@
}
/**
- * Find the next node names that can be used. These will be derived from the tag and the
+ * Find the next node names that can be used. These will be derived from the group and the
* template. We will pre-allocate a specified quantity, and attempt to verify that there is no
* name conflict with the current service.
*
- * @param tag
+ * @param group
* @param count
* @param template
* @return
*/
- protected Set<String> getNextNames(final String tag, final Template template, int count) {
+ protected Set<String> getNextNames(final String group, final Template template, int count) {
Set<String> names = newLinkedHashSet();
Iterable<? extends ComputeMetadata> currentNodes = listNodesStrategy.listNodes();
int maxTries = 100;
int currentTries = 0;
while (names.size() < count && currentTries++ < maxTries) {
- final String name = getNextName(tag, template);
+ final String name = getNextName(group, template);
if (!any(currentNodes, new Predicate<ComputeMetadata>() {
@Override
@@ -159,14 +159,14 @@
}
/**
- * Get a name using a random mechanism that still ties all nodes in a tag together.
+ * Get a name using a random mechanism that still ties all nodes in a group together.
*
- * This implementation will pass the tag and a hex formatted random number to the configured
+ * This implementation will pass the group and a hex formatted random number to the configured
* naming convention.
*
*/
- protected String getNextName(final String tag, final Template template) {
- return String.format(nodeNamingConvention, tag, Integer.toHexString(new SecureRandom().nextInt(4095)));
+ protected String getNextName(final String group, final Template template) {
+ return String.format(nodeNamingConvention, group, Integer.toHexString(new SecureRandom().nextInt(4095)));
}
}
\ No newline at end of file
diff --git a/compute/src/main/java/org/jclouds/compute/strategy/impl/ReturnCredentialsBoundToImage.java b/compute/src/main/java/org/jclouds/compute/strategy/impl/ReturnCredentialsBoundToImage.java
index 5eae255..0d58fbe 100644
--- a/compute/src/main/java/org/jclouds/compute/strategy/impl/ReturnCredentialsBoundToImage.java
+++ b/compute/src/main/java/org/jclouds/compute/strategy/impl/ReturnCredentialsBoundToImage.java
@@ -51,7 +51,8 @@
@Override
public LoginCredentials apply(Object resourceToAuthenticate) {
- checkState(resourceToAuthenticate instanceof Image, "this is only valid for images");
+ checkState(resourceToAuthenticate instanceof Image, "this is only valid for images, not %s",
+ resourceToAuthenticate.getClass().getSimpleName());
if (creds != null)
return creds;
Image image = Image.class.cast(resourceToAuthenticate);
diff --git a/compute/src/main/java/org/jclouds/ovf/xml/internal/BaseEnvelopeHandler.java b/compute/src/main/java/org/jclouds/ovf/xml/internal/BaseEnvelopeHandler.java
index 98406ed..6248658 100644
--- a/compute/src/main/java/org/jclouds/ovf/xml/internal/BaseEnvelopeHandler.java
+++ b/compute/src/main/java/org/jclouds/ovf/xml/internal/BaseEnvelopeHandler.java
@@ -131,6 +131,9 @@
} else if (equalsOrSuffix(qName, "NetworkSection")) {
inNetwork = false;
builder.networkSection(networkHandler.getResult());
+ } else if (equalsOrSuffix(qName, "VirtualSystemCollection")) {
+ // http://code.google.com/p/jclouds/issues/detail?id=811
+ throw new IllegalArgumentException("this handler cannot currently create envelopes with multiple virtual systems");
} else if (equalsOrSuffix(qName, "VirtualSystem")) {
inVirtualSystem = false;
builder.virtualSystem(virtualSystemHandler.getResult());
diff --git a/compute/src/test/java/org/jclouds/compute/BaseTemplateBuilderLiveTest.java b/compute/src/test/java/org/jclouds/compute/BaseTemplateBuilderLiveTest.java
index 160c6b4..cfd5d3f 100644
--- a/compute/src/test/java/org/jclouds/compute/BaseTemplateBuilderLiveTest.java
+++ b/compute/src/test/java/org/jclouds/compute/BaseTemplateBuilderLiveTest.java
@@ -281,12 +281,12 @@
assertEquals(context.getComputeService().templateBuilder().build().getImage().getDefaultCredentials(),
LoginCredentials.builder().user(user).password(pass).authenticateSudo(auth).build());
} finally {
- if (context != null)
+ if (context != null){
+ // Need to clear persisted credentials; otherwise next time a ComputeServiceContext is created
+ // then it will have these "foo" credentials!
+ context.credentialStore().clear();
context.close();
-
- // Need to clear persisted credentials; otherwise next time a ComputeServiceContext is created
- // then it will have these "foo" credentials!
- context.credentialStore().clear();
+ }
}
}
diff --git a/compute/src/test/java/org/jclouds/compute/RunScriptData.java b/compute/src/test/java/org/jclouds/compute/RunScriptData.java
index 8aa5cc8..d2eafcd 100644
--- a/compute/src/test/java/org/jclouds/compute/RunScriptData.java
+++ b/compute/src/test/java/org/jclouds/compute/RunScriptData.java
@@ -149,18 +149,23 @@
public static String aptInstall = "apt-get install -f -y -qq --force-yes";
+ public static String aptInstallLazyUpgrade(String packageName) {
+ return aptInstall + " " + packageName + "|| (" + "apt-get update -qq&&" + "apt-get upgrade -y -qq" + ")&&"
+ + aptInstall + " " + packageName;
+ }
+
public static final Statement APT_RUN_SCRIPT = newStatementList(//
+ exec("which nslookup >&- 2>&-|| " + aptInstallLazyUpgrade("dnsutils")),//
normalizeHostAndDNSConfig(),//
- exec("which curl >&- 2>&-|| " + aptInstall + " curl"),//
- exec("which nslookup >&- 2>&-|| " + aptInstall + " dnsutils"),//
+ exec("which curl >&- 2>&-|| " + aptInstallLazyUpgrade("curl")),//
JDK7_INSTALL_TGZ);
public static String yumInstall = "yum --nogpgcheck -y install";
public static final Statement YUM_RUN_SCRIPT = newStatementList(//
+ exec("which nslookup >&- 2>&-|| " + yumInstall + " bind-utils"),//
normalizeHostAndDNSConfig(),//
exec("which curl >&- 2>&-|| " + yumInstall + " curl"),//
- exec("which nslookup >&- 2>&-|| " + yumInstall + " bind-utils"),//
JDK7_INSTALL_TGZ);
public static final Statement ZYPPER_RUN_SCRIPT = newStatementList(//
diff --git a/compute/src/test/java/org/jclouds/compute/domain/internal/TemplateBuilderImplTest.java b/compute/src/test/java/org/jclouds/compute/domain/internal/TemplateBuilderImplTest.java
index 260e09d..c979c78 100644
--- a/compute/src/test/java/org/jclouds/compute/domain/internal/TemplateBuilderImplTest.java
+++ b/compute/src/test/java/org/jclouds/compute/domain/internal/TemplateBuilderImplTest.java
@@ -18,10 +18,10 @@
*/
package org.jclouds.compute.domain.internal;
+import static org.easymock.EasyMock.createMock;
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.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
import static org.testng.Assert.assertEquals;
import java.util.NoSuchElementException;
@@ -49,9 +49,50 @@
*
* @author Adrian Cole
*/
-@Test(groups = "unit")
+@Test(groups = "unit", singleThreaded = true)
public class TemplateBuilderImplTest {
+
+ @SuppressWarnings("unchecked")
+ public void testLocationPredicateWhenComputeMetadataIsNotLocationBound() {
+ Location defaultLocation = createMock(Location.class);
+ Image image = createMock(Image.class);
+ OperatingSystem os = createMock(OperatingSystem.class);
+ Hardware hardware = new HardwareBuilder().id("hardwareId").build();
+
+ Supplier<Set<? extends Location>> locations = Suppliers.<Set<? extends Location>> ofInstance(ImmutableSet
+ .<Location> of(defaultLocation));
+ Supplier<Set<? extends Image>> images = Suppliers.<Set<? extends Image>> ofInstance(ImmutableSet.<Image> of(
+ image));
+ Supplier<Set<? extends Hardware>> hardwares = Suppliers.<Set<? extends Hardware>> ofInstance(ImmutableSet
+ .<Hardware> of(hardware));
+ Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
+ Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);
+ TemplateBuilder defaultTemplate = createMock(TemplateBuilder.class);
+
+ expect(image.getLocation()).andReturn(defaultLocation).anyTimes();
+ expect(image.getProviderId()).andReturn("imageId").anyTimes();
+ expect(defaultLocation.getId()).andReturn("location").anyTimes();
+
+ replay(image);
+ replay(os);
+ replay(defaultTemplate);
+ replay(defaultLocation);
+ replay(optionsProvider);
+ replay(templateBuilderProvider);
+
+ TemplateBuilderImpl template = createTemplateBuilder(null, locations, images, hardwares, defaultLocation,
+ optionsProvider, templateBuilderProvider);
+ assert template.locationPredicate.apply(hardware);
+
+ verify(image);
+ verify(os);
+ verify(defaultTemplate);
+ verify(defaultLocation);
+ verify(optionsProvider);
+ verify(templateBuilderProvider);
+ }
+
@SuppressWarnings("unchecked")
@Test
public void testResolveImages() {
@@ -75,6 +116,8 @@
expect(image.getName()).andReturn("imageName");
expect(image2.getName()).andReturn("imageName");
+ expect(image.getDescription()).andReturn("imageDescription");
+ expect(image2.getDescription()).andReturn("imageDescription");
expect(image.getVersion()).andReturn("imageVersion");
expect(image2.getVersion()).andReturn("imageVersion");
expect(image.getOperatingSystem()).andReturn(os).atLeastOnce();
@@ -179,7 +222,7 @@
@SuppressWarnings("unchecked")
@Test
- public void testSizeWithImageIdPredicateOnlyAcceptsImage() {
+ public void testHardwareWithImageIdPredicateOnlyAcceptsImage() {
Location defaultLocation = createMock(Location.class);
Image image = createMock(Image.class);
OperatingSystem os = createMock(OperatingSystem.class);
@@ -239,7 +282,56 @@
@SuppressWarnings("unchecked")
@Test
- public void testSizeWithImageIdPredicateOnlyDoesntImage() {
+ public void testHardwareWithImageIdPredicateOnlyAcceptsImageWhenLocationNull() {
+ Location defaultLocation = createMock(Location.class);
+ Image image = createMock(Image.class);
+ OperatingSystem os = createMock(OperatingSystem.class);
+
+ Hardware hardware = new HardwareBuilder().id("hardwareId").supportsImage(ImagePredicates.idEquals("myregion/imageId"))
+ .build();
+
+ Supplier<Set<? extends Location>> locations = Suppliers.<Set<? extends Location>> ofInstance(ImmutableSet
+ .<Location> of(defaultLocation));
+ Supplier<Set<? extends Image>> images = Suppliers.<Set<? extends Image>> ofInstance(ImmutableSet
+ .<Image> of(image));
+ Supplier<Set<? extends Hardware>> hardwares = Suppliers.<Set<? extends Hardware>> ofInstance(ImmutableSet
+ .<Hardware> of(hardware));
+ Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
+ Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);
+ TemplateBuilder defaultTemplate = createMock(TemplateBuilder.class);
+
+ expect(optionsProvider.get()).andReturn(new TemplateOptions());
+ expect(image.getId()).andReturn("myregion/imageId").atLeastOnce();
+ expect(image.getLocation()).andReturn(null).atLeastOnce();
+ expect(image.getName()).andReturn(null).atLeastOnce();
+ expect(image.getDescription()).andReturn(null).atLeastOnce();
+ expect(image.getVersion()).andReturn(null).atLeastOnce();
+ expect(image.getOperatingSystem()).andReturn(os).atLeastOnce();
+ expect(image.getProviderId()).andReturn("imageId").anyTimes();
+
+ expect(defaultLocation.getId()).andReturn("myregion").anyTimes();
+
+ expect(os.getName()).andReturn(null).atLeastOnce();
+ expect(os.getVersion()).andReturn(null).atLeastOnce();
+ expect(os.getFamily()).andReturn(null).atLeastOnce();
+ expect(os.getDescription()).andReturn(null).atLeastOnce();
+ expect(os.getArch()).andReturn(null).atLeastOnce();
+ expect(os.is64Bit()).andReturn(false).atLeastOnce();
+
+ replay(image, os, defaultTemplate, defaultLocation, optionsProvider, templateBuilderProvider);
+
+ TemplateBuilderImpl template = createTemplateBuilder(null, locations, images, hardwares, defaultLocation,
+ optionsProvider, templateBuilderProvider);
+
+ template.imageId("myregion/imageId").build();
+
+ verify(image, os, defaultTemplate, defaultLocation, optionsProvider, templateBuilderProvider);
+
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testHardwareWithImageIdPredicateOnlyDoesntImage() {
Location defaultLocation = createMock(Location.class);
Image image = createMock(Image.class);
OperatingSystem os = createMock(OperatingSystem.class);
@@ -567,9 +659,8 @@
Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);
TemplateOptions defaultOptions = createMock(TemplateOptions.class);
- expect(defaultLocation.getId()).andReturn("us-east-1");
-
expect(optionsProvider.get()).andReturn(defaultOptions);
+ expect(defaultLocation.getId()).andReturn("us-east-1");
replay(defaultOptions);
replay(defaultLocation);
@@ -580,11 +671,11 @@
optionsProvider, templateBuilderProvider);
try {
- template.imageDescriptionMatches("region/ami").build();
+ template.imageDescriptionMatches("description").build();
assert false;
} catch (NoSuchElementException e) {
// make sure big data is not in the exception message
- assertEquals(e.getMessage(), "no image matched predicate: And(locationEqualsOrChildOf(us-east-1),imageDescription(region/ami))");
+ assertEquals(e.getMessage(), "no image matched predicate: And(locationEqualsOrChildOf(us-east-1),imageDescription(description))");
}
verify(defaultOptions);
diff --git a/compute/src/test/java/org/jclouds/ovf/xml/EnvelopeHandlerTest.java b/compute/src/test/java/org/jclouds/ovf/xml/EnvelopeHandlerTest.java
index b2c657c..19be6cd 100644
--- a/compute/src/test/java/org/jclouds/ovf/xml/EnvelopeHandlerTest.java
+++ b/compute/src/test/java/org/jclouds/ovf/xml/EnvelopeHandlerTest.java
@@ -38,13 +38,27 @@
@Test(groups = "unit")
public class EnvelopeHandlerTest {
public void testVCloud1_0() {
- InputStream is = getClass().getResourceAsStream("/ovf.xml");
- Injector injector = Guice.createInjector(new SaxParserModule());
- Factory factory = injector.getInstance(ParseSax.Factory.class);
- Envelope result = factory.create(injector.getInstance(EnvelopeHandler.class)).parse(is);
+ Envelope result = parseEnvelope();
checkOvfEnvelope(result);
}
+ public static Envelope parseEnvelope() {
+ InputStream is = EnvelopeHandlerTest.class.getResourceAsStream("/ovf.xml");
+ Injector injector = Guice.createInjector(new SaxParserModule());
+ Factory factory = injector.getInstance(ParseSax.Factory.class);
+ Envelope result = factory.create(injector.getInstance(EnvelopeHandler.class)).parse(is);
+ return result;
+ }
+
+ //TODO: create a parser that can!
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void testThrowIllegalArgumentAsWeDontYetSupportVirtualSystemCollections() {
+ InputStream is = getClass().getResourceAsStream("/ovf-vcd1.5.xml");
+ Injector injector = Guice.createInjector(new SaxParserModule());
+ Factory factory = injector.getInstance(ParseSax.Factory.class);
+ factory.create(injector.getInstance(EnvelopeHandler.class)).parse(is).getVirtualSystem();
+ }
+
static void checkOvfEnvelope(Envelope result) {
VirtualSystemSettingDataHandlerTest.checkVirtualSystem(result.getVirtualSystem());
}
diff --git a/compute/src/test/resources/initscript_with_java.sh b/compute/src/test/resources/initscript_with_java.sh
index 898ff24..b0494d5 100644
--- a/compute/src/test/resources/initscript_with_java.sh
+++ b/compute/src/test/resources/initscript_with_java.sh
@@ -99,10 +99,10 @@
/etc/init.d/sshd reload||/etc/init.d/ssh reload
awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(randompassword)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}}
test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow
+which nslookup >&- 2>&-|| apt-get install -f -y -qq --force-yes dnsutils|| (apt-get update -qq&&apt-get upgrade -y -qq)&&apt-get install -f -y -qq --force-yes dnsutils
grep `hostname` /etc/hosts >/dev/null || awk -v hostname=`hostname` 'END { print $1" "hostname }' /proc/net/arp >> /etc/hosts
nslookup yahoo.com >/dev/null || echo nameserver 208.67.222.222 >> /etc/resolv.conf
-which curl >&- 2>&-|| apt-get install -f -y -qq --force-yes curl
-which nslookup >&- 2>&-|| apt-get install -f -y -qq --force-yes dnsutils
+which curl >&- 2>&-|| apt-get install -f -y -qq --force-yes curl|| (apt-get update -qq&&apt-get upgrade -y -qq)&&apt-get install -f -y -qq --force-yes curl
mkdir -p /usr/local/jdk
curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.oracle.com/otn-pub/java/jdk/7u2-b13/jdk-7u2-linux-x64.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -)
mv /usr/local/jdk1.7*/* /usr/local/jdk/
diff --git a/compute/src/test/resources/initscript_with_jboss.sh b/compute/src/test/resources/initscript_with_jboss.sh
index 5ffab24..c9ea3f3 100644
--- a/compute/src/test/resources/initscript_with_jboss.sh
+++ b/compute/src/test/resources/initscript_with_jboss.sh
@@ -99,10 +99,10 @@
/etc/init.d/sshd reload||/etc/init.d/ssh reload
awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(randompassword)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}}
test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow
+which nslookup >&- 2>&-|| apt-get install -f -y -qq --force-yes dnsutils|| (apt-get update -qq&&apt-get upgrade -y -qq)&&apt-get install -f -y -qq --force-yes dnsutils
grep `hostname` /etc/hosts >/dev/null || awk -v hostname=`hostname` 'END { print $1" "hostname }' /proc/net/arp >> /etc/hosts
nslookup yahoo.com >/dev/null || echo nameserver 208.67.222.222 >> /etc/resolv.conf
-which curl >&- 2>&-|| apt-get install -f -y -qq --force-yes curl
-which nslookup >&- 2>&-|| apt-get install -f -y -qq --force-yes dnsutils
+which curl >&- 2>&-|| apt-get install -f -y -qq --force-yes curl|| (apt-get update -qq&&apt-get upgrade -y -qq)&&apt-get install -f -y -qq --force-yes curl
mkdir -p /usr/local/jdk
curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.oracle.com/otn-pub/java/jdk/7u2-b13/jdk-7u2-linux-x64.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -)
mv /usr/local/jdk1.7*/* /usr/local/jdk/
diff --git a/compute/src/test/resources/ovf-vcd1.5.xml b/compute/src/test/resources/ovf-vcd1.5.xml
new file mode 100644
index 0000000..d815e42
--- /dev/null
+++ b/compute/src/test/resources/ovf-vcd1.5.xml
@@ -0,0 +1,338 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ovf:Envelope xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" xmlns:vcloud="http://www.vmware.com/vcloud/v1" xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2.22.0/CIM_VirtualSystemSettingData.xsd http://schemas.dmtf.org/ovf/envelope/1 http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2.22.0/CIM_ResourceAllocationSettingData.xsd http://www.vmware.com/vcloud/v1 http://109.233.49.135/api/v1.0/schema/master.xsd">
+ <ovf:References/>
+ <ovf:NetworkSection>
+ <ovf:Info>The list of logical networks</ovf:Info>
+ <ovf:Network ovf:name="int">
+ <ovf:Description/>
+ </ovf:Network>
+ <ovf:Network ovf:name="StratoGen Ext Net">
+ <ovf:Description/>
+ </ovf:Network>
+ </ovf:NetworkSection>
+ <vcloud:NetworkConfigSection ovf:required="false">
+ <ovf:Info>The configuration parameters for logical networks</ovf:Info>
+ <vcloud:NetworkConfig networkName="int">
+ <vcloud:Description/>
+ <vcloud:Configuration>
+ <vcloud:IpScope>
+ <vcloud:IsInherited>false</vcloud:IsInherited>
+ <vcloud:Gateway>192.168.2.1</vcloud:Gateway>
+ <vcloud:Netmask>255.255.255.0</vcloud:Netmask>
+ <vcloud:Dns1>109.233.48.141</vcloud:Dns1>
+ <vcloud:IpRanges>
+ <vcloud:IpRange>
+ <vcloud:StartAddress>192.168.2.100</vcloud:StartAddress>
+ <vcloud:EndAddress>192.168.2.199</vcloud:EndAddress>
+ </vcloud:IpRange>
+ </vcloud:IpRanges>
+ </vcloud:IpScope>
+ <vcloud:FenceMode>isolated</vcloud:FenceMode>
+ <vcloud:Features>
+ <vcloud:DhcpService>
+ <vcloud:IsEnabled>false</vcloud:IsEnabled>
+ <vcloud:DefaultLeaseTime>3600</vcloud:DefaultLeaseTime>
+ <vcloud:MaxLeaseTime>7200</vcloud:MaxLeaseTime>
+ <vcloud:IpRange>
+ <vcloud:StartAddress>192.168.2.2</vcloud:StartAddress>
+ <vcloud:EndAddress>192.168.2.99</vcloud:EndAddress>
+ </vcloud:IpRange>
+ </vcloud:DhcpService>
+ </vcloud:Features>
+ </vcloud:Configuration>
+ <vcloud:IsDeployed>false</vcloud:IsDeployed>
+ </vcloud:NetworkConfig>
+ <vcloud:NetworkConfig networkName="StratoGen Ext Net">
+ <vcloud:Description/>
+ <vcloud:Configuration>
+ <vcloud:IpScope>
+ <vcloud:IsInherited>true</vcloud:IsInherited>
+ <vcloud:Gateway>212.54.128.1</vcloud:Gateway>
+ <vcloud:Netmask>255.255.255.0</vcloud:Netmask>
+ <vcloud:Dns1>109.233.48.141</vcloud:Dns1>
+ <vcloud:Dns2>109.233.48.142</vcloud:Dns2>
+ <vcloud:IpRanges>
+ <vcloud:IpRange>
+ <vcloud:StartAddress>212.54.128.4</vcloud:StartAddress>
+ <vcloud:EndAddress>212.54.128.220</vcloud:EndAddress>
+ </vcloud:IpRange>
+ </vcloud:IpRanges>
+ </vcloud:IpScope>
+ <vcloud:FenceMode>bridged</vcloud:FenceMode>
+ <vcloud:Features>
+ <vcloud:DhcpService>
+ <vcloud:IsEnabled>false</vcloud:IsEnabled>
+ <vcloud:DefaultLeaseTime>3600</vcloud:DefaultLeaseTime>
+ <vcloud:MaxLeaseTime>7200</vcloud:MaxLeaseTime>
+ <vcloud:IpRange>
+ <vcloud:StartAddress>212.54.128.2</vcloud:StartAddress>
+ <vcloud:EndAddress>212.54.128.3</vcloud:EndAddress>
+ </vcloud:IpRange>
+ </vcloud:DhcpService>
+ <vcloud:FirewallService>
+ <vcloud:IsEnabled>true</vcloud:IsEnabled>
+ </vcloud:FirewallService>
+ <vcloud:NatService>
+ <vcloud:IsEnabled>true</vcloud:IsEnabled>
+ <vcloud:NatType>ipTranslation</vcloud:NatType>
+ <vcloud:Policy>allowTraffic</vcloud:Policy>
+ <vcloud:NatRule>
+ <vcloud:OneToOneVmRule>
+ <vcloud:MappingMode>automatic</vcloud:MappingMode>
+ <vcloud:VAppScopedVmId>72591b67-ea8f-4ae8-8a05-3e0a857d1e7b</vcloud:VAppScopedVmId>
+ <vcloud:VmNicId>0</vcloud:VmNicId>
+ </vcloud:OneToOneVmRule>
+ </vcloud:NatRule>
+ </vcloud:NatService>
+ </vcloud:Features>
+ </vcloud:Configuration>
+ <vcloud:IsDeployed>false</vcloud:IsDeployed>
+ </vcloud:NetworkConfig>
+ </vcloud:NetworkConfigSection>
+ <vcloud:LeaseSettingsSection ovf:required="false">
+ <ovf:Info>Lease settings section</ovf:Info>
+ <vcloud:DeploymentLeaseInSeconds>0</vcloud:DeploymentLeaseInSeconds>
+ <vcloud:StorageLeaseInSeconds>0</vcloud:StorageLeaseInSeconds>
+ </vcloud:LeaseSettingsSection>
+ <vcloud:CustomizationSection ovf:required="false">
+ <ovf:Info>VApp template customization section</ovf:Info>
+ <vcloud:CustomizeOnInstantiate>true</vcloud:CustomizeOnInstantiate>
+ </vcloud:CustomizationSection>
+ <ovf:VirtualSystemCollection ovf:id="Windows 2008 R2 Standard (base) no service pack">
+ <ovf:Info>A collection of virtual machines: </ovf:Info>
+ <ovf:Name>Windows 2008 R2 Standard (base) no service pack</ovf:Name>
+ <ovf:StartupSection>
+ <ovf:Info>VApp startup section</ovf:Info>
+ <ovf:Item ovf:stopDelay="0" ovf:stopAction="powerOff" ovf:startDelay="0" ovf:startAction="powerOn" ovf:order="0" ovf:id="Windows 2008 R2 Standard (Base) NO SP1"/>
+ <ovf:Item ovf:stopDelay="0" ovf:stopAction="powerOff" ovf:startDelay="0" ovf:startAction="powerOn" ovf:order="0" ovf:id="Windows 2008R2 Standard "/>
+ </ovf:StartupSection>
+ <ovf:VirtualSystem ovf:id="Windows 2008R2 Standard ">
+ <ovf:Info>A virtual machine: Standard Edition</ovf:Info>
+ <ovf:Name>Windows 2008R2 Standard </ovf:Name>
+ <ovf:OperatingSystemSection xmlns:vmw="http://www.vmware.com/schema/ovf" ovf:id="102" vmw:osType="windows7Server64Guest">
+ <ovf:Info>Specifies the operating system installed</ovf:Info>
+ <ovf:Description>Microsoft Windows Server 2008 R2 (64-bit)</ovf:Description>
+ </ovf:OperatingSystemSection>
+ <ovf:VirtualHardwareSection>
+ <ovf:Info>Virtual hardware requirements</ovf:Info>
+ <ovf:System>
+ <vssd:ElementName>Virtual Hardware Family</vssd:ElementName>
+ <vssd:InstanceID>0</vssd:InstanceID>
+ <vssd:VirtualSystemIdentifier>Windows 2008R2 Standard </vssd:VirtualSystemIdentifier>
+ <vssd:VirtualSystemType>vmx-07</vssd:VirtualSystemType>
+ </ovf:System>
+ <ovf:Item>
+ <rasd:Address>00:50:56:01:00:02</rasd:Address>
+ <rasd:AddressOnParent>0</rasd:AddressOnParent>
+ <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
+ <rasd:Connection vcloud:ipAddress="212.54.128.101" vcloud:primaryNetworkConnection="true" vcloud:ipAddressingMode="POOL">StratoGen Ext Net</rasd:Connection>
+ <rasd:Description>PCNet32 ethernet adapter</rasd:Description>
+ <rasd:ElementName>Network adapter 0</rasd:ElementName>
+ <rasd:InstanceID>1</rasd:InstanceID>
+ <rasd:ResourceSubType>PCNet32</rasd:ResourceSubType>
+ <rasd:ResourceType>10</rasd:ResourceType>
+ </ovf:Item>
+ <ovf:Item>
+ <rasd:Address>0</rasd:Address>
+ <rasd:Description>SCSI Controller</rasd:Description>
+ <rasd:ElementName>SCSI Controller 0</rasd:ElementName>
+ <rasd:InstanceID>2</rasd:InstanceID>
+ <rasd:ResourceSubType>lsilogicsas</rasd:ResourceSubType>
+ <rasd:ResourceType>6</rasd:ResourceType>
+ </ovf:Item>
+ <ovf:Item>
+ <rasd:AddressOnParent>0</rasd:AddressOnParent>
+ <rasd:Description>Hard disk</rasd:Description>
+ <rasd:ElementName>Hard disk 1</rasd:ElementName>
+ <rasd:HostResource vcloud:capacity="51200" vcloud:busType="6" vcloud:busSubType="lsilogicsas"/>
+ <rasd:InstanceID>2000</rasd:InstanceID>
+ <rasd:Parent>2</rasd:Parent>
+ <rasd:ResourceType>17</rasd:ResourceType>
+ </ovf:Item>
+ <ovf:Item>
+ <rasd:Address>0</rasd:Address>
+ <rasd:Description>IDE Controller</rasd:Description>
+ <rasd:ElementName>IDE Controller 0</rasd:ElementName>
+ <rasd:InstanceID>3</rasd:InstanceID>
+ <rasd:ResourceType>5</rasd:ResourceType>
+ </ovf:Item>
+ <ovf:Item>
+ <rasd:AddressOnParent>0</rasd:AddressOnParent>
+ <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
+ <rasd:Description>CD/DVD Drive</rasd:Description>
+ <rasd:ElementName>CD/DVD Drive 1</rasd:ElementName>
+ <rasd:HostResource/>
+ <rasd:InstanceID>3000</rasd:InstanceID>
+ <rasd:Parent>3</rasd:Parent>
+ <rasd:ResourceType>15</rasd:ResourceType>
+ </ovf:Item>
+ <ovf:Item>
+ <rasd:AddressOnParent>0</rasd:AddressOnParent>
+ <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
+ <rasd:Description>Floppy Drive</rasd:Description>
+ <rasd:ElementName>Floppy Drive 1</rasd:ElementName>
+ <rasd:HostResource/>
+ <rasd:InstanceID>8000</rasd:InstanceID>
+ <rasd:ResourceType>14</rasd:ResourceType>
+ </ovf:Item>
+ <ovf:Item>
+ <rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>
+ <rasd:Description>Number of Virtual CPUs</rasd:Description>
+ <rasd:ElementName>1 virtual CPU(s)</rasd:ElementName>
+ <rasd:InstanceID>4</rasd:InstanceID>
+ <rasd:Reservation>0</rasd:Reservation>
+ <rasd:ResourceType>3</rasd:ResourceType>
+ <rasd:VirtualQuantity>1</rasd:VirtualQuantity>
+ <rasd:Weight>0</rasd:Weight>
+ </ovf:Item>
+ <ovf:Item>
+ <rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>
+ <rasd:Description>Memory Size</rasd:Description>
+ <rasd:ElementName>2048 MB of memory</rasd:ElementName>
+ <rasd:InstanceID>5</rasd:InstanceID>
+ <rasd:Reservation>0</rasd:Reservation>
+ <rasd:ResourceType>4</rasd:ResourceType>
+ <rasd:VirtualQuantity>2048</rasd:VirtualQuantity>
+ <rasd:Weight>0</rasd:Weight>
+ </ovf:Item>
+ </ovf:VirtualHardwareSection>
+ <vcloud:NetworkConnectionSection ovf:required="false">
+ <ovf:Info>Specifies the available VM network connections</ovf:Info>
+ <vcloud:PrimaryNetworkConnectionIndex>0</vcloud:PrimaryNetworkConnectionIndex>
+ <vcloud:NetworkConnection network="StratoGen Ext Net">
+ <vcloud:NetworkConnectionIndex>0</vcloud:NetworkConnectionIndex>
+ <vcloud:IpAddress>212.54.128.101</vcloud:IpAddress>
+ <vcloud:IsConnected>true</vcloud:IsConnected>
+ <vcloud:MACAddress>00:50:56:01:00:02</vcloud:MACAddress>
+ <vcloud:IpAddressAllocationMode>POOL</vcloud:IpAddressAllocationMode>
+ </vcloud:NetworkConnection>
+ </vcloud:NetworkConnectionSection>
+ <vcloud:GuestCustomizationSection ovf:required="false">
+ <ovf:Info>Specifies Guest OS Customization Settings</ovf:Info>
+ <vcloud:Enabled>true</vcloud:Enabled>
+ <vcloud:ChangeSid>true</vcloud:ChangeSid>
+ <vcloud:JoinDomainEnabled>false</vcloud:JoinDomainEnabled>
+ <vcloud:UseOrgSettings>false</vcloud:UseOrgSettings>
+ <vcloud:AdminPasswordEnabled>true</vcloud:AdminPasswordEnabled>
+ <vcloud:AdminPasswordAuto>true</vcloud:AdminPasswordAuto>
+ <vcloud:AdminPassword>7qS$$3d#</vcloud:AdminPassword>
+ <vcloud:ResetPasswordRequired>false</vcloud:ResetPasswordRequired>
+ <vcloud:ComputerName>WindowsServ-0</vcloud:ComputerName>
+ </vcloud:GuestCustomizationSection>
+ </ovf:VirtualSystem>
+ <ovf:VirtualSystem ovf:id="Windows 2008 R2 Standard (Base) NO SP1">
+ <ovf:Info>A virtual machine: Windows 2008 R2 Standard Edition[\r]</ovf:Info>
+ <ovf:Name>Windows 2008 R2 Standard (Base) NO SP1</ovf:Name>
+ <ovf:OperatingSystemSection xmlns:vmw="http://www.vmware.com/schema/ovf" ovf:id="102" vmw:osType="windows7Server64Guest">
+ <ovf:Info>Specifies the operating system installed</ovf:Info>
+ <ovf:Description>Microsoft Windows Server 2008 R2 (64-bit)</ovf:Description>
+ </ovf:OperatingSystemSection>
+ <ovf:VirtualHardwareSection>
+ <ovf:Info>Virtual hardware requirements</ovf:Info>
+ <ovf:System>
+ <vssd:ElementName>Virtual Hardware Family</vssd:ElementName>
+ <vssd:InstanceID>0</vssd:InstanceID>
+ <vssd:VirtualSystemIdentifier>Windows 2008 R2 Standard (Base) NO SP1</vssd:VirtualSystemIdentifier>
+ <vssd:VirtualSystemType>vmx-07</vssd:VirtualSystemType>
+ </ovf:System>
+ <ovf:Item>
+ <rasd:Address>00:50:56:01:02:38</rasd:Address>
+ <rasd:AddressOnParent>0</rasd:AddressOnParent>
+ <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
+ <rasd:Connection vcloud:ipAddress="192.168.2.100" vcloud:primaryNetworkConnection="true" vcloud:ipAddressingMode="POOL">int</rasd:Connection>
+ <rasd:Description>PCNet32 ethernet adapter</rasd:Description>
+ <rasd:ElementName>Network adapter 0</rasd:ElementName>
+ <rasd:InstanceID>1</rasd:InstanceID>
+ <rasd:ResourceSubType>PCNet32</rasd:ResourceSubType>
+ <rasd:ResourceType>10</rasd:ResourceType>
+ </ovf:Item>
+ <ovf:Item>
+ <rasd:Address>0</rasd:Address>
+ <rasd:Description>SCSI Controller</rasd:Description>
+ <rasd:ElementName>SCSI Controller 0</rasd:ElementName>
+ <rasd:InstanceID>2</rasd:InstanceID>
+ <rasd:ResourceSubType>lsilogicsas</rasd:ResourceSubType>
+ <rasd:ResourceType>6</rasd:ResourceType>
+ </ovf:Item>
+ <ovf:Item>
+ <rasd:AddressOnParent>0</rasd:AddressOnParent>
+ <rasd:Description>Hard disk</rasd:Description>
+ <rasd:ElementName>Hard disk 1</rasd:ElementName>
+ <rasd:HostResource vcloud:capacity="51200" vcloud:busType="6" vcloud:busSubType="lsilogicsas"/>
+ <rasd:InstanceID>2000</rasd:InstanceID>
+ <rasd:Parent>2</rasd:Parent>
+ <rasd:ResourceType>17</rasd:ResourceType>
+ </ovf:Item>
+ <ovf:Item>
+ <rasd:Address>0</rasd:Address>
+ <rasd:Description>IDE Controller</rasd:Description>
+ <rasd:ElementName>IDE Controller 0</rasd:ElementName>
+ <rasd:InstanceID>3</rasd:InstanceID>
+ <rasd:ResourceType>5</rasd:ResourceType>
+ </ovf:Item>
+ <ovf:Item>
+ <rasd:AddressOnParent>0</rasd:AddressOnParent>
+ <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
+ <rasd:Description>CD/DVD Drive</rasd:Description>
+ <rasd:ElementName>CD/DVD Drive 1</rasd:ElementName>
+ <rasd:HostResource/>
+ <rasd:InstanceID>3000</rasd:InstanceID>
+ <rasd:Parent>3</rasd:Parent>
+ <rasd:ResourceType>15</rasd:ResourceType>
+ </ovf:Item>
+ <ovf:Item>
+ <rasd:AddressOnParent>0</rasd:AddressOnParent>
+ <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
+ <rasd:Description>Floppy Drive</rasd:Description>
+ <rasd:ElementName>Floppy Drive 1</rasd:ElementName>
+ <rasd:HostResource/>
+ <rasd:InstanceID>8000</rasd:InstanceID>
+ <rasd:ResourceType>14</rasd:ResourceType>
+ </ovf:Item>
+ <ovf:Item>
+ <rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>
+ <rasd:Description>Number of Virtual CPUs</rasd:Description>
+ <rasd:ElementName>1 virtual CPU(s)</rasd:ElementName>
+ <rasd:InstanceID>4</rasd:InstanceID>
+ <rasd:Reservation>0</rasd:Reservation>
+ <rasd:ResourceType>3</rasd:ResourceType>
+ <rasd:VirtualQuantity>1</rasd:VirtualQuantity>
+ <rasd:Weight>0</rasd:Weight>
+ </ovf:Item>
+ <ovf:Item>
+ <rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>
+ <rasd:Description>Memory Size</rasd:Description>
+ <rasd:ElementName>2048 MB of memory</rasd:ElementName>
+ <rasd:InstanceID>5</rasd:InstanceID>
+ <rasd:Reservation>0</rasd:Reservation>
+ <rasd:ResourceType>4</rasd:ResourceType>
+ <rasd:VirtualQuantity>2048</rasd:VirtualQuantity>
+ <rasd:Weight>0</rasd:Weight>
+ </ovf:Item>
+ </ovf:VirtualHardwareSection>
+ <vcloud:NetworkConnectionSection ovf:required="false">
+ <ovf:Info>Specifies the available VM network connections</ovf:Info>
+ <vcloud:PrimaryNetworkConnectionIndex>0</vcloud:PrimaryNetworkConnectionIndex>
+ <vcloud:NetworkConnection network="int">
+ <vcloud:NetworkConnectionIndex>0</vcloud:NetworkConnectionIndex>
+ <vcloud:IpAddress>192.168.2.100</vcloud:IpAddress>
+ <vcloud:IsConnected>true</vcloud:IsConnected>
+ <vcloud:MACAddress>00:50:56:01:02:38</vcloud:MACAddress>
+ <vcloud:IpAddressAllocationMode>POOL</vcloud:IpAddressAllocationMode>
+ </vcloud:NetworkConnection>
+ </vcloud:NetworkConnectionSection>
+ <vcloud:GuestCustomizationSection ovf:required="false">
+ <ovf:Info>Specifies Guest OS Customization Settings</ovf:Info>
+ <vcloud:Enabled>true</vcloud:Enabled>
+ <vcloud:ChangeSid>true</vcloud:ChangeSid>
+ <vcloud:JoinDomainEnabled>false</vcloud:JoinDomainEnabled>
+ <vcloud:UseOrgSettings>false</vcloud:UseOrgSettings>
+ <vcloud:AdminPasswordEnabled>true</vcloud:AdminPasswordEnabled>
+ <vcloud:AdminPasswordAuto>true</vcloud:AdminPasswordAuto>
+ <vcloud:AdminPassword>4cV!Lunc</vcloud:AdminPassword>
+ <vcloud:ResetPasswordRequired>false</vcloud:ResetPasswordRequired>
+ <vcloud:ComputerName>WindowsServer20</vcloud:ComputerName>
+ </vcloud:GuestCustomizationSection>
+ </ovf:VirtualSystem>
+ </ovf:VirtualSystemCollection>
+</ovf:Envelope>
\ No newline at end of file
diff --git a/compute/src/test/resources/runscript.sh b/compute/src/test/resources/runscript.sh
index 2d24707..d20f61a 100644
--- a/compute/src/test/resources/runscript.sh
+++ b/compute/src/test/resources/runscript.sh
@@ -78,10 +78,10 @@
# add desired commands from the user
cat >> $INSTANCE_HOME/runScriptWithCreds.sh <<'END_OF_SCRIPT'
cd $INSTANCE_HOME
+which nslookup >&- 2>&-|| apt-get install -f -y -qq --force-yes dnsutils|| (apt-get update -qq&&apt-get upgrade -y -qq)&&apt-get install -f -y -qq --force-yes dnsutils
grep `hostname` /etc/hosts >/dev/null || awk -v hostname=`hostname` 'END { print $1" "hostname }' /proc/net/arp >> /etc/hosts
nslookup yahoo.com >/dev/null || echo nameserver 208.67.222.222 >> /etc/resolv.conf
-which curl >&- 2>&-|| apt-get install -f -y -qq --force-yes curl
-which nslookup >&- 2>&-|| apt-get install -f -y -qq --force-yes dnsutils
+which curl >&- 2>&-|| apt-get install -f -y -qq --force-yes curl|| (apt-get update -qq&&apt-get upgrade -y -qq)&&apt-get install -f -y -qq --force-yes curl
mkdir -p /usr/local/jdk
curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.oracle.com/otn-pub/java/jdk/7u2-b13/jdk-7u2-linux-x64.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -)
mv /usr/local/jdk1.7*/* /usr/local/jdk/
diff --git a/core/pom.xml b/core/pom.xml
index ebb06b6..a8aa286 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -38,21 +38,6 @@
<url>http://jclouds.googlecode.com/svn/trunk</url>
</scm>
- <repositories>
- <!-- TODO to be removed when the dependencies are in central -->
- <!-- https://issues.sonatype.org/browse/OSSRH-1453 -->
- <repository>
- <id>jersey</id>
- <url>http://download.java.net/maven/2</url>
- <releases>
- <enabled>true</enabled>
- </releases>
- <snapshots>
- <enabled>false</enabled>
- </snapshots>
- </repository>
- </repositories>
-
<dependencies>
<dependency>
<groupId>net.oauth.core</groupId>
@@ -74,7 +59,7 @@
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
- <version>1.6</version>
+ <version>1.11</version>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
@@ -109,7 +94,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
- <version>11.0</version>
+ <version>11.0.1</version>
</dependency>
</dependencies>
diff --git a/core/src/main/java/org/jclouds/collect/TransformingSetSupplier.java b/core/src/main/java/org/jclouds/collect/TransformingSetSupplier.java
index 899b07c..2010e8b 100644
--- a/core/src/main/java/org/jclouds/collect/TransformingSetSupplier.java
+++ b/core/src/main/java/org/jclouds/collect/TransformingSetSupplier.java
@@ -19,13 +19,15 @@
package org.jclouds.collect;
import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Predicates.notNull;
+import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.transform;
-import static com.google.common.collect.Sets.newLinkedHashSet;
import java.util.Set;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableSet;
/**
*
@@ -42,7 +44,7 @@
@Override
public Set<? extends T> get() {
- return newLinkedHashSet(transform(backingSupplier.get(), converter));
+ return ImmutableSet.copyOf(filter(transform(filter(backingSupplier.get(), notNull()), converter), notNull()));
}
}
diff --git a/core/src/main/java/org/jclouds/concurrent/RetryOnTimeOutExceptionFunction.java b/core/src/main/java/org/jclouds/concurrent/RetryOnTimeOutExceptionFunction.java
new file mode 100644
index 0000000..c2fd9f9
--- /dev/null
+++ b/core/src/main/java/org/jclouds/concurrent/RetryOnTimeOutExceptionFunction.java
@@ -0,0 +1,77 @@
+/**
+ * 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.concurrent;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Throwables.propagate;
+
+import java.util.concurrent.TimeoutException;
+
+import org.jclouds.util.Throwables2;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ForwardingObject;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+public class RetryOnTimeOutExceptionFunction<K,V> extends ForwardingObject implements Function<K,V>{
+ private final Function<K,V> delegate;
+
+ public RetryOnTimeOutExceptionFunction(Function<K,V> delegate) {
+ this.delegate = checkNotNull(delegate, "delegate");
+ }
+
+ //TODO: backoff limited retry handler
+ @Override
+ public V apply(K key) {
+ TimeoutException ex = null;
+ for (int i = 0; i < 3; i++) {
+ try {
+ ex = null;
+ return delegate().apply(key);
+ } catch (Exception e) {
+ if ((ex = Throwables2.getFirstThrowableOfType(e, TimeoutException.class)) != null)
+ continue;
+ throw propagate(e);
+ }
+ }
+ if (ex != null)
+ throw propagate(ex);
+ assert false;
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return delegate.equals(obj);
+ }
+
+ @Override
+ public int hashCode() {
+ return delegate.hashCode();
+ }
+
+ @Override
+ protected Function<K,V> delegate() {
+ return delegate;
+ }
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/jclouds/http/functions/ParseSax.java b/core/src/main/java/org/jclouds/http/functions/ParseSax.java
index 6a6948c..04f284f 100644
--- a/core/src/main/java/org/jclouds/http/functions/ParseSax.java
+++ b/core/src/main/java/org/jclouds/http/functions/ParseSax.java
@@ -21,18 +21,20 @@
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.io.Closeables.closeQuietly;
+import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
-import javax.inject.Inject;
+import javax.annotation.Resource;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.logging.Logger;
import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest;
-import org.jclouds.util.Strings2;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
@@ -41,6 +43,7 @@
import com.google.common.base.Function;
import com.google.common.base.Throwables;
+import com.google.common.io.Closeables;
/**
* This object will parse the body of an HttpResponse and return the result of type <T> back to the
@@ -50,6 +53,9 @@
*/
public class ParseSax<T> implements Function<HttpResponse, T>, InvocationContext<ParseSax<T>> {
+ @Resource
+ private Logger logger = Logger.NULL;
+
private final XMLReader parser;
private final HandlerWithResult<T> handler;
private HttpRequest request;
@@ -58,7 +64,6 @@
<T> ParseSax<T> create(HandlerWithResult<T> handler);
}
- @Inject
public ParseSax(XMLReader parser, HandlerWithResult<T> handler) {
this.parser = checkNotNull(parser, "parser");
this.handler = checkNotNull(handler, "handler");
@@ -71,34 +76,45 @@
} catch (NullPointerException e) {
return addDetailsAndPropagate(from, e);
}
- if (from.getStatusCode() >= 300)
- return convertStreamToStringAndParse(from);
- InputStream is = from.getPayload().getInput();
+ InputStream is = null;
try {
+ // debug is more normally set, so trace is more appropriate for
+ // something heavy like this
+ if (from.getStatusCode() >= 300 || logger.isTraceEnabled())
+ return convertStreamToStringAndParse(from);
+ is = from.getPayload().getInput();
return parse(new InputSource(is));
} catch (RuntimeException e) {
return addDetailsAndPropagate(from, e);
} finally {
- closeQuietly(is);
+ Closeables.closeQuietly(is);
+ from.getPayload().release();
}
}
- private T convertStreamToStringAndParse(HttpResponse from) {
+ private T convertStreamToStringAndParse(HttpResponse response) {
+ String from = null;
try {
- return parse(Strings2.toStringAndClose(from.getPayload().getInput()));
+ from = new String(closeClientButKeepContentStream(response));
+ validateXml(from);
+ return doParse(new InputSource(new StringReader(from)));
} catch (Exception e) {
- return addDetailsAndPropagate(from, e);
+ return addDetailsAndPropagate(response, e, from);
}
}
public T parse(String from) {
try {
- checkNotNull(from, "xml string");
- checkArgument(from.indexOf('<') >= 0, String.format("not an xml document [%s] ", from));
- } catch (RuntimeException e) {
- return addDetailsAndPropagate(null, e);
+ validateXml(from);
+ return doParse(new InputSource(new StringReader(from)));
+ } catch (Exception e) {
+ return addDetailsAndPropagate(null, e, from);
}
- return parse(new InputSource(new StringReader(from)));
+ }
+
+ private void validateXml(String from) {
+ checkNotNull(from, "xml string");
+ checkArgument(from.indexOf('<') >= 0, String.format("not an xml document [%s] ", from));
}
public T parse(InputStream from) {
@@ -127,6 +143,10 @@
}
public T addDetailsAndPropagate(HttpResponse response, Exception e) {
+ return addDetailsAndPropagate(response, e, null);
+ }
+
+ public T addDetailsAndPropagate(HttpResponse response, Exception e, @Nullable String text) {
StringBuilder message = new StringBuilder();
if (request != null) {
message.append("request: ").append(request.getRequestLine());
@@ -144,15 +164,16 @@
}
if (message.length() != 0)
message.append("; ");
- message.append(String.format("error at %d:%d in document %s", parseException.getColumnNumber(),
- parseException.getLineNumber(), systemId));
+ message.append(String.format("error at %d:%d in document %s", parseException.getColumnNumber(), parseException
+ .getLineNumber(), systemId));
}
+ if (text != null)
+ message.append("; source:\n").append(text);
if (message.length() != 0) {
message.append("; cause: ").append(e.toString());
throw new RuntimeException(message.toString(), e);
} else {
- Throwables.propagate(e);
- return null;
+ throw Throwables.propagate(e);
}
}
@@ -167,7 +188,7 @@
* @author Adrian Cole
*/
public abstract static class HandlerWithResult<T> extends DefaultHandler implements
- InvocationContext<HandlerWithResult<T>> {
+ InvocationContext<HandlerWithResult<T>> {
private HttpRequest request;
protected HttpRequest getRequest() {
diff --git a/core/src/main/java/org/jclouds/http/functions/config/SaxParserModule.java b/core/src/main/java/org/jclouds/http/functions/config/SaxParserModule.java
index 48625d0..9ea5089 100644
--- a/core/src/main/java/org/jclouds/http/functions/config/SaxParserModule.java
+++ b/core/src/main/java/org/jclouds/http/functions/config/SaxParserModule.java
@@ -27,7 +27,9 @@
import org.jclouds.http.functions.ParseSax.HandlerWithResult;
import org.xml.sax.XMLReader;
+import com.google.common.base.Throwables;
import com.google.inject.AbstractModule;
+import com.google.inject.Injector;
import com.google.inject.Provides;
import com.google.inject.Scopes;
@@ -42,18 +44,27 @@
bind(ParseSax.Factory.class).to(Factory.class).in(Scopes.SINGLETON);
}
- private static class Factory implements ParseSax.Factory {
+ static class Factory implements ParseSax.Factory {
+ private final SAXParserFactory factory;
+ private final Injector i;
+
@Inject
- private SAXParserFactory factory;
+ Factory(SAXParserFactory factory, Injector i) {
+ this.factory = factory;
+ this.i = i;
+ }
public <T> ParseSax<T> create(HandlerWithResult<T> handler) {
SAXParser saxParser;
try {
saxParser = factory.newSAXParser();
XMLReader parser = saxParser.getXMLReader();
- return new ParseSax<T>(parser, handler);
+ // TODO: switch to @AssistedInject
+ ParseSax<T> returnVal = new ParseSax<T>(parser, handler);
+ i.injectMembers(returnVal);
+ return returnVal;
} catch (Exception e) {
- throw new RuntimeException(e);
+ throw Throwables.propagate(e);
}
}
diff --git a/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpCommandExecutorService.java b/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpCommandExecutorService.java
index 19d7361..50ef222 100644
--- a/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpCommandExecutorService.java
+++ b/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpCommandExecutorService.java
@@ -51,6 +51,7 @@
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.Constants;
+import org.jclouds.JcloudsVersion;
import org.jclouds.crypto.CryptoStreams;
import org.jclouds.http.HttpCommandExecutorService;
import org.jclouds.http.HttpRequest;
@@ -77,7 +78,9 @@
@Singleton
public class JavaUrlHttpCommandExecutorService extends BaseHttpCommandExecutorService<HttpURLConnection> {
- public static final String USER_AGENT = "jclouds/1.0 java/" + System.getProperty("java.version");
+ public static final String USER_AGENT = String.format("jclouds/%s java/%s", JcloudsVersion.get(), System
+ .getProperty("java.version"));
+
@Resource
protected Logger logger = Logger.NULL;
private final Supplier<SSLContext> untrustedSSLContextProvider;
diff --git a/core/src/main/java/org/jclouds/predicates/validators/DnsNameValidator.java b/core/src/main/java/org/jclouds/predicates/validators/DnsNameValidator.java
index 06fe200..74db196 100644
--- a/core/src/main/java/org/jclouds/predicates/validators/DnsNameValidator.java
+++ b/core/src/main/java/org/jclouds/predicates/validators/DnsNameValidator.java
@@ -43,7 +43,7 @@
private int max;
@Inject
- protected DnsNameValidator(@Named("jclouds.dns_name_length_min") int min,
+ public DnsNameValidator(@Named("jclouds.dns_name_length_min") int min,
@Named("jclouds.dns_name_length_max") int max) {
this.min = min;
this.max = max;
diff --git a/core/src/main/java/org/jclouds/util/Throwables2.java b/core/src/main/java/org/jclouds/util/Throwables2.java
index 559dfe7..00fa94d 100644
--- a/core/src/main/java/org/jclouds/util/Throwables2.java
+++ b/core/src/main/java/org/jclouds/util/Throwables2.java
@@ -31,6 +31,7 @@
import org.jclouds.rest.ResourceNotFoundException;
import com.google.common.base.Throwables;
+import com.google.inject.CreationException;
import com.google.inject.ProvisionException;
import com.google.inject.spi.Message;
@@ -45,6 +46,8 @@
public static <T extends Throwable> T getFirstThrowableOfType(Throwable from, Class<T> clazz) {
if (from instanceof ProvisionException)
return getFirstThrowableOfType(ProvisionException.class.cast(from), clazz);
+ else if (from instanceof CreationException)
+ return getFirstThrowableOfType(CreationException.class.cast(from), clazz);
try {
return (T) find(getCausalChain(from), instanceOf(clazz));
} catch (NoSuchElementException e) {
@@ -58,6 +61,22 @@
T cause = getFirstThrowableOfType(message.getCause(), clazz);
if (cause instanceof ProvisionException)
return getFirstThrowableOfType(ProvisionException.class.cast(cause), clazz);
+ else if (cause instanceof CreationException)
+ return getFirstThrowableOfType(CreationException.class.cast(cause), clazz);
+ return cause;
+ }
+ }
+ return null;
+ }
+
+ public static <T extends Throwable> T getFirstThrowableOfType(CreationException e, Class<T> clazz) {
+ for (Message message : e.getErrorMessages()) {
+ if (message.getCause() != null) {
+ T cause = getFirstThrowableOfType(message.getCause(), clazz);
+ if (cause instanceof ProvisionException)
+ return getFirstThrowableOfType(ProvisionException.class.cast(cause), clazz);
+ else if (cause instanceof CreationException)
+ return getFirstThrowableOfType(CreationException.class.cast(cause), clazz);
return cause;
}
}
diff --git a/core/src/main/resources/rest.properties b/core/src/main/resources/rest.properties
index 9120345..892fead 100644
--- a/core/src/main/resources/rest.properties
+++ b/core/src/main/resources/rest.properties
@@ -141,8 +141,8 @@
ibm-smartcloud.propertiesbuilder=org.jclouds.ibm.smartcloud.IBMSmartCloudPropertiesBuilder
ibm-smartcloud.contextbuilder=org.jclouds.ibm.smartcloud.IBMSmartCloudContextBuilder
-virtacore-vcloudexpress.propertiesbuilder=org.jclouds.virtacore.vcloudexpress.VirtacoreVCloudExpressPropertiesBuilder
-virtacore-vcloudexpress.contextbuilder=org.jclouds.virtacore.vcloudexpress.VirtacoreVCloudExpressContextBuilder
+virtacore-publiccloud-lax.propertiesbuilder=org.jclouds.virtacore.publiccloud.VirtacorePublicCloudLAXPropertiesBuilder
+virtacore-publiccloud-lax.contextbuilder=org.jclouds.virtacore.publiccloud.VirtacorePublicCloudLAXContextBuilder
dunkel-vcd.propertiesbuilder=org.jclouds.dunkel.vcd.DunkelVCloudDirectorPropertiesBuilder
dunkel-vcd.contextbuilder=org.jclouds.dunkel.vcd.DunkelVCloudDirectorContextBuilder
diff --git a/core/src/test/java/org/jclouds/collect/TransformingSetSupplierTest.java b/core/src/test/java/org/jclouds/collect/TransformingSetSupplierTest.java
new file mode 100644
index 0000000..3b01670
--- /dev/null
+++ b/core/src/test/java/org/jclouds/collect/TransformingSetSupplierTest.java
@@ -0,0 +1,65 @@
+/**
+ * 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.collect;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", singleThreaded = true, testName = "TransformingSetSupplierTest")
+public class TransformingSetSupplierTest {
+ @Test
+ public void testTransform() {
+ TransformingSetSupplier<String, String> supplier = new TransformingSetSupplier<String, String>(Suppliers
+ .<Iterable<String>> ofInstance(ImmutableSet.of("foo")), Functions.forMap(ImmutableMap.of("foo", "bar")));
+ assertEquals(supplier.get(), ImmutableSet.<String> of("bar"));
+ }
+
+ @Test
+ public void testNullsNotReturnedFromSourceSupplier() {
+ List<String> ofNull = Lists.newArrayList();
+ ofNull.add(null);
+
+ TransformingSetSupplier<String, String> supplier = new TransformingSetSupplier<String, String>(Suppliers
+ .<Iterable<String>> ofInstance(ofNull), Functions.forMap(ImmutableMap.of("foo", "bar")));
+ assertEquals(supplier.get(), ImmutableSet.<String> of());
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testNullsNotReturnedFromFunction() {
+ TransformingSetSupplier<String, String> supplier = new TransformingSetSupplier<String, String>(Suppliers
+ .<Iterable<String>> ofInstance(ImmutableSet.of("foo")), (Function) Functions.constant(null));
+ assertEquals(supplier.get(), ImmutableSet.<String> of());
+ }
+
+}
diff --git a/core/src/test/java/org/jclouds/concurrent/RetryOnTimeOutExceptionFunctionTest.java b/core/src/test/java/org/jclouds/concurrent/RetryOnTimeOutExceptionFunctionTest.java
new file mode 100644
index 0000000..4b2136e
--- /dev/null
+++ b/core/src/test/java/org/jclouds/concurrent/RetryOnTimeOutExceptionFunctionTest.java
@@ -0,0 +1,126 @@
+/**
+ * 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.concurrent;
+
+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.testng.Assert.assertEquals;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeoutException;
+
+import org.jclouds.rest.AuthorizationException;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Function;
+
+/**
+ * Tests behavior of RetryOnTimeOutExceptionFunction
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", singleThreaded = true, testName = "RetryOnTimeOutExceptionFunctionTest")
+public class RetryOnTimeOutExceptionFunctionTest {
+ ExecutorService executorService = MoreExecutors.sameThreadExecutor();
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testGetThrowsOriginalExceptionButRetriesOnTimeoutException() throws InterruptedException, ExecutionException {
+ Function<String, String> delegate = createMock(Function.class);
+ TimeoutException timeout = createMock(TimeoutException.class);
+ RuntimeException throwable = new RuntimeException(timeout);
+
+ expect(delegate.apply("baz")).andThrow(throwable);
+ expect(timeout.getCause()).andReturn(null).anyTimes();
+ expect(delegate.apply("baz")).andThrow(throwable);
+ expect(delegate.apply("baz")).andThrow(throwable);
+
+ replay(delegate);
+ replay(timeout);
+
+ RetryOnTimeOutExceptionFunction<String, String> supplier = new RetryOnTimeOutExceptionFunction<String, String>(
+ delegate);
+ try {
+ supplier.apply("baz");
+ assert false;
+ } catch (RuntimeException e) {
+ assertEquals(e.getCause(), timeout);
+ }
+
+ verify(delegate);
+ verify(timeout);
+
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testGetAllowsTwoFailuresOnTimeoutException() throws InterruptedException, ExecutionException {
+ Function<String, String> delegate = createMock(Function.class);
+ TimeoutException timeout = createMock(TimeoutException.class);
+ RuntimeException throwable = new RuntimeException(timeout);
+
+ expect(delegate.apply("baz")).andThrow(throwable);
+ expect(timeout.getCause()).andReturn(null).anyTimes();
+ expect(delegate.apply("baz")).andThrow(throwable);
+ expect(delegate.apply("baz")).andReturn("foo");
+
+ replay(delegate);
+ replay(timeout);
+
+ RetryOnTimeOutExceptionFunction<String, String> supplier = new RetryOnTimeOutExceptionFunction<String, String>(
+ delegate);
+ assertEquals(supplier.apply("baz"), "foo");
+
+ verify(delegate);
+ verify(timeout);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testGetAllowsNoFailuresOnOtherExceptions() throws InterruptedException, ExecutionException {
+ Function<String, String> delegate = createMock(Function.class);
+ AuthorizationException auth = createMock(AuthorizationException.class);
+ RuntimeException throwable = new RuntimeException(auth);
+
+ expect(delegate.apply("baz")).andThrow(throwable);
+ expect(auth.getCause()).andReturn(null).anyTimes();
+
+
+ replay(delegate);
+ replay(auth);
+
+ RetryOnTimeOutExceptionFunction<String, String> supplier = new RetryOnTimeOutExceptionFunction<String, String>(
+ delegate);
+
+ try {
+ supplier.apply("baz");
+ assert false;
+ } catch (RuntimeException e) {
+ assertEquals(e.getCause(), auth);
+ }
+
+ verify(delegate);
+ verify(auth);
+
+ }
+
+}
diff --git a/core/src/test/java/org/jclouds/http/JavaUrlHttpCommandExecutorServiceIntegrationTest.java b/core/src/test/java/org/jclouds/http/JavaUrlHttpCommandExecutorServiceIntegrationTest.java
index 4e71445..e64008d 100644
--- a/core/src/test/java/org/jclouds/http/JavaUrlHttpCommandExecutorServiceIntegrationTest.java
+++ b/core/src/test/java/org/jclouds/http/JavaUrlHttpCommandExecutorServiceIntegrationTest.java
@@ -27,6 +27,7 @@
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.http.internal.JavaUrlHttpCommandExecutorService;
+import org.testng.annotations.Test;
import com.google.inject.Module;
@@ -35,6 +36,7 @@
*
* @author Adrian Cole
*/
+@Test
public class JavaUrlHttpCommandExecutorServiceIntegrationTest extends BaseHttpCommandExecutorServiceIntegrationTest {
protected Module createConnectionModule() {
diff --git a/core/src/test/java/org/jclouds/rest/BaseRestClientExpectTest.java b/core/src/test/java/org/jclouds/rest/BaseRestClientExpectTest.java
index 61b54f2..ad8dca8 100644
--- a/core/src/test/java/org/jclouds/rest/BaseRestClientExpectTest.java
+++ b/core/src/test/java/org/jclouds/rest/BaseRestClientExpectTest.java
@@ -23,14 +23,15 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.jclouds.rest.RestContextFactory.contextSpec;
import static org.jclouds.rest.RestContextFactory.createContext;
+import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.Properties;
+import java.util.Map.Entry;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;
@@ -60,8 +61,8 @@
import com.google.common.annotations.Beta;
import com.google.common.base.Function;
-import com.google.common.base.Functions;
import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -146,6 +147,18 @@
return Payloads.newInputStreamPayload(getClass().getResourceAsStream(resource));
}
+ public Payload payloadFromResourceWithContentType(String resource, String contentType) {
+ try {
+ Payload payload = Payloads.newStringPayload(Strings2
+ .toStringAndClose(getClass().getResourceAsStream(resource)));
+ payload.getContentMetadata().setContentType(contentType);
+ return payload;
+ } catch (IOException e) {
+ throw Throwables.propagate(e);
+ }
+
+ }
+
/**
* Mock executor service which uses the supplied function to return http responses.
*/
@@ -214,11 +227,11 @@
public S requestSendsResponse(HttpRequest request, HttpResponse response) {
return requestSendsResponse(request, response, createModule());
}
-
+
public S requestSendsResponse(HttpRequest request, HttpResponse response, Module module) {
return requestsSendResponses(ImmutableMap.of(request, response), module);
}
-
+
/**
* creates a client for a mock server which only responds to two types of requests
*
@@ -263,14 +276,11 @@
HttpResponse responseB, HttpRequest requestC, HttpResponse responseC) {
return requestsSendResponses(requestA, responseA, requestB, responseB, requestC, responseC, createModule());
}
-
+
public S requestsSendResponses(HttpRequest requestA, HttpResponse responseA, HttpRequest requestB,
HttpResponse responseB, HttpRequest requestC, HttpResponse responseC, Module module) {
- return requestsSendResponses(ImmutableMap.of(requestA, responseA, requestB, responseB, requestC, responseC), module);
- }
-
- public S orderedRequestsSendResponses(HttpRequest requestA, HttpResponse responseA) {
- return orderedRequestsSendResponses(ImmutableList.of(requestA), ImmutableList.of(responseA));
+ return requestsSendResponses(ImmutableMap.of(requestA, responseA, requestB, responseB, requestC, responseC),
+ module);
}
public S orderedRequestsSendResponses(HttpRequest requestA, HttpResponse responseA, HttpRequest requestB,
@@ -280,25 +290,29 @@
public S orderedRequestsSendResponses(HttpRequest requestA, HttpResponse responseA, HttpRequest requestB,
HttpResponse responseB, HttpRequest requestC, HttpResponse responseC) {
- return orderedRequestsSendResponses(ImmutableList.of(requestA, requestB, requestC), ImmutableList.of(responseA, responseB, responseC));
+ return orderedRequestsSendResponses(ImmutableList.of(requestA, requestB, requestC), ImmutableList.of(responseA,
+ responseB, responseC));
}
public S orderedRequestsSendResponses(HttpRequest requestA, HttpResponse responseA, HttpRequest requestB,
- HttpResponse responseB, HttpRequest requestC, HttpResponse responseC, HttpRequest requestD, HttpResponse responseD) {
- return orderedRequestsSendResponses(ImmutableList.of(requestA, requestB, requestC, requestD), ImmutableList.of(responseA, responseB, responseC, responseD));
+ HttpResponse responseB, HttpRequest requestC, HttpResponse responseC, HttpRequest requestD,
+ HttpResponse responseD) {
+ return orderedRequestsSendResponses(ImmutableList.of(requestA, requestB, requestC, requestD), ImmutableList.of(
+ responseA, responseB, responseC, responseD));
}
public S orderedRequestsSendResponses(final List<HttpRequest> requests, final List<HttpResponse> responses) {
final AtomicInteger counter = new AtomicInteger(0);
-
- return createClient(new Function<HttpRequest,HttpResponse>() {
+
+ return createClient(new Function<HttpRequest, HttpResponse>() {
@Override
public HttpResponse apply(HttpRequest input) {
int index = counter.getAndIncrement();
- if (index >= requests.size()) {
- throw new IndexOutOfBoundsException("request index "+index+", but only "+requests.size()+" request/response pairs");
- }
- assert input.equals(requests.get(index)) : "expected="+requests.get(index)+"; actual="+input;
+ if (index >= requests.size())
+ return HttpResponse.builder().statusCode(500).message(
+ String.format("request %s is out of range (%s)", index, requests.size())).payload(
+ Payloads.newStringPayload(renderRequest(input))).build();
+ assertEquals(renderRequest(input), renderRequest(requests.get(index)));
return responses.get(index);
}
});
@@ -316,8 +330,21 @@
return requestsSendResponses(requestToResponse, createModule());
}
- public S requestsSendResponses(Map<HttpRequest, HttpResponse> requestToResponse, Module module) {
- return createClient(Functions.forMap(requestToResponse), module);
+ public S requestsSendResponses(final Map<HttpRequest, HttpResponse> requestToResponse, Module module) {
+ return createClient(new Function<HttpRequest, HttpResponse>() {
+ ImmutableBiMap<HttpRequest, HttpResponse> bimap = ImmutableBiMap.copyOf(requestToResponse);
+
+ @Override
+ public HttpResponse apply(HttpRequest input) {
+ if (!(requestToResponse.containsKey(input)))
+ return HttpResponse.builder().statusCode(500).message("no response configured for request").payload(
+ Payloads.newStringPayload(renderRequest(input))).build();
+ HttpResponse response = requestToResponse.get(input);
+ // in case hashCode/equals doesn't do a full content check
+ assertEquals(renderRequest(input), renderRequest(bimap.inverse().get(response)));
+ return response;
+ }
+ }, module);
}
public String renderRequest(HttpRequest request) {
diff --git a/core/src/test/java/org/jclouds/util/Suppliers2Test.java b/core/src/test/java/org/jclouds/util/Suppliers2Test.java
index 9319451..41c669d 100644
--- a/core/src/test/java/org/jclouds/util/Suppliers2Test.java
+++ b/core/src/test/java/org/jclouds/util/Suppliers2Test.java
@@ -37,7 +37,6 @@
import com.google.common.base.Function;
import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
public class Suppliers2Test {
diff --git a/core/src/test/java/org/jclouds/util/Throwables2Test.java b/core/src/test/java/org/jclouds/util/Throwables2Test.java
index ecc89b9..20110eb 100644
--- a/core/src/test/java/org/jclouds/util/Throwables2Test.java
+++ b/core/src/test/java/org/jclouds/util/Throwables2Test.java
@@ -18,8 +18,8 @@
*/
package org.jclouds.util;
-import static org.easymock.classextension.EasyMock.createMock;
-import static org.easymock.classextension.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.createNiceMock;
import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
import static org.jclouds.util.Throwables2.returnFirstExceptionIfInListOrThrowStandardExceptionOrCause;
import static org.testng.Assert.assertEquals;
@@ -37,6 +37,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.inject.CreationException;
import com.google.inject.ProvisionException;
import com.google.inject.spi.Message;
@@ -46,12 +47,6 @@
@Test
public class Throwables2Test {
- public void testGetCause() {
- AuthorizationException aex = createMock(AuthorizationException.class);
- Message message = new Message(ImmutableList.of(), "test", aex);
- ProvisionException pex = new ProvisionException(ImmutableSet.of(message));
- assertEquals(getFirstThrowableOfType(pex, AuthorizationException.class), aex);
- }
public void testGetFirstThrowableOfTypeSubclass() {
SocketException aex = createMock(SocketException.class);
@@ -62,6 +57,13 @@
AuthorizationException aex = createMock(AuthorizationException.class);
assertEquals(getFirstThrowableOfType(aex, AuthorizationException.class), aex);
}
+
+ public void testGetCause() {
+ AuthorizationException aex = createMock(AuthorizationException.class);
+ Message message = new Message(ImmutableList.of(), "test", aex);
+ ProvisionException pex = new ProvisionException(ImmutableSet.of(message));
+ assertEquals(getFirstThrowableOfType(pex, AuthorizationException.class), aex);
+ }
public void testGetFirstThrowableOfTypeInner() {
AuthorizationException aex = createMock(AuthorizationException.class);
@@ -83,6 +85,34 @@
assertEquals(getFirstThrowableOfType(pex, AuthorizationException.class), null);
}
+
+ public void testGetCauseCreation() {
+ AuthorizationException aex = createMock(AuthorizationException.class);
+ Message message = new Message(ImmutableList.of(), "test", aex);
+ CreationException pex = new CreationException(ImmutableSet.of(message));
+ assertEquals(getFirstThrowableOfType(pex, AuthorizationException.class), aex);
+ }
+
+ public void testGetFirstThrowableOfTypeInnerCreation() {
+ AuthorizationException aex = createMock(AuthorizationException.class);
+ Message message = new Message(ImmutableList.of(), "test", aex);
+ CreationException pex = new CreationException(ImmutableSet.of(message));
+ assertEquals(getFirstThrowableOfType(pex, AuthorizationException.class), aex);
+ }
+
+ public void testGetFirstThrowableOfTypeFailCreation() {
+ TimeoutException aex = createMock(TimeoutException.class);
+ Message message = new Message(ImmutableList.of(), "test", aex);
+ CreationException pex = new CreationException(ImmutableSet.of(message));
+ assertEquals(getFirstThrowableOfType(pex, AuthorizationException.class), null);
+ }
+
+ public void testGetFirstThrowableOfTypeWhenCauseIsNullCreation() {
+ Message message = new Message(ImmutableList.of(), "test", null);
+ CreationException pex = new CreationException(ImmutableSet.of(message));
+ assertEquals(getFirstThrowableOfType(pex, AuthorizationException.class), null);
+ }
+
@Test
public void testReturnExceptionThatsInList() throws Exception {
Exception e = new TestException();
@@ -135,6 +165,13 @@
ImmutableList.of(), "Error in custom provider",e))));
}
+ @Test(expectedExceptions = AuthorizationException.class)
+ public void testPropagateCreationExceptionAuthorizationException() throws Exception {
+ Exception e = new AuthorizationException();
+ returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(new Class[] {}, new CreationException(ImmutableSet.of(new Message(
+ ImmutableList.of(), "Error in custom provider",e))));
+ }
+
@Test(expectedExceptions = InsufficientResourcesException.class)
public void testPropagateStandardExceptionInsufficientResourcesException() throws Exception {
Exception e = new InsufficientResourcesException();
diff --git a/demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/config/SpringServletConfig.java b/demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/config/SpringServletConfig.java
index 4d9e5d5..53189d4 100644
--- a/demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/config/SpringServletConfig.java
+++ b/demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/config/SpringServletConfig.java
@@ -18,7 +18,6 @@
*/
package org.jclouds.demo.tweetstore.config;
-import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Predicates.in;
@@ -47,6 +46,7 @@
import org.jclouds.blobstore.BlobStoreContextFactory;
import org.jclouds.demo.tweetstore.config.util.CredentialsCollector;
import org.jclouds.demo.tweetstore.controller.AddTweetsController;
+import org.jclouds.demo.tweetstore.controller.EnqueueStoresController;
import org.jclouds.demo.tweetstore.controller.StoreTweetsController;
import org.jclouds.demo.tweetstore.functions.ServiceToStoredTweetStatuses;
import org.jclouds.gae.config.GoogleAppEngineConfigurationModule;
@@ -65,7 +65,6 @@
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
-import com.google.appengine.api.taskqueue.TaskOptions.Method;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
@@ -121,10 +120,7 @@
// get a queue for submitting store tweet requests
queue = QueueFactory.getQueue("twitter");
- // submit a job to store tweets for each configured blobstore
- for (String name : providerTypeToBlobStoreMap.keySet()) {
- queue.add(withUrl("/store/do").header("context", name).method(Method.GET));
- }
+
logger.trace("Members initialized. Twitter: '%s', container: '%s', provider types: '%s'", twitterClient,
container, providerTypeToBlobStoreMap.keySet());
}
@@ -169,6 +165,11 @@
return controller;
}
+ @Bean
+ public EnqueueStoresController enqueueStoresController() {
+ return new EnqueueStoresController(providerTypeToBlobStoreMap, queue);
+ }
+
private void injectServletConfig(Servlet servlet) {
logger.trace("About to inject servlet config '%s'", servletConfig);
try {
@@ -190,10 +191,11 @@
Map<String, Object> urlMap = Maps.newHashMapWithExpectedSize(2);
urlMap.put("/store/*", storeTweetsController());
urlMap.put("/tweets/*", addTweetsController());
+ urlMap.put("/stores/*", enqueueStoresController());
mapping.setUrlMap(urlMap);
/*
- * "/store" and "/tweets" are part of the servlet mapping and thus stripped by the mapping if
- * using default settings.
+ * "/store", "/tweets" and "/stores" are part of the servlet mapping and thus
+ * stripped by the mapping if using default settings.
*/
mapping.setAlwaysUseFullPath(true);
return mapping;
diff --git a/demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresController.java b/demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresController.java
new file mode 100644
index 0000000..94568e4
--- /dev/null
+++ b/demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresController.java
@@ -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.demo.tweetstore.controller;
+
+import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl;
+import static com.google.appengine.repackaged.com.google.common.base.Strings.nullToEmpty;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.blobstore.BlobStoreContext;
+import org.jclouds.logging.Logger;
+
+import com.google.appengine.api.taskqueue.Queue;
+import com.google.appengine.api.taskqueue.TaskOptions.Method;
+import com.google.common.annotations.VisibleForTesting;
+
+/**
+ * Adds tasks to retrieve and store tweets in all registered contexts to an async
+ * task queue.
+ *
+ * @author Andrew Phillips
+ * @see StoreTweetsController
+ */
+@Singleton
+public class EnqueueStoresController extends HttpServlet {
+ /** The serialVersionUID */
+ private static final long serialVersionUID = 7215420527854203714L;
+
+ private final Set<String> contextNames;
+ private final Queue taskQueue;
+
+ @Resource
+ protected Logger logger = Logger.NULL;
+
+ @Inject
+ public EnqueueStoresController(Map<String, BlobStoreContext> contexts,
+ Queue taskQueue) {
+ contextNames = contexts.keySet();
+ this.taskQueue = taskQueue;
+ }
+
+ @VisibleForTesting
+ void enqueueStoreTweetTasks() {
+ for (String contextName : contextNames) {
+ logger.debug("enqueuing task to store tweets in blobstore '%s'", contextName);
+ taskQueue.add(withUrl("/store/do").header("context", contextName).method(Method.GET));
+ }
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ if (!nullToEmpty(request.getHeader("X-AppEngine-Cron")).equals("true")) {
+ response.sendError(401);
+ }
+
+ try {
+ enqueueStoreTweetTasks();
+ response.setContentType(MediaType.TEXT_PLAIN);
+ response.getWriter().println("Done!");
+ } catch (Exception e) {
+ logger.error(e, "Error storing tweets");
+ throw new ServletException(e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/demos/tweetstore/gae-tweetstore-spring/src/main/platform/cron.xml b/demos/tweetstore/gae-tweetstore-spring/src/main/platform/cron.xml
new file mode 100644
index 0000000..193a540
--- /dev/null
+++ b/demos/tweetstore/gae-tweetstore-spring/src/main/platform/cron.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+ 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.
+
+-->
+<cronentries>
+ <cron>
+ <url>/stores/do</url>
+ <description>Enqueue 'store tweet' tasks for all contexts</description>
+ <schedule>every 10 minutes</schedule>
+ </cron>
+</cronentries>
\ No newline at end of file
diff --git a/demos/tweetstore/gae-tweetstore-spring/src/main/webapp/WEB-INF/queue.xml b/demos/tweetstore/gae-tweetstore-spring/src/main/webapp/WEB-INF/queue.xml
index e8c42d7..1bc53f3 100644
--- a/demos/tweetstore/gae-tweetstore-spring/src/main/webapp/WEB-INF/queue.xml
+++ b/demos/tweetstore/gae-tweetstore-spring/src/main/webapp/WEB-INF/queue.xml
@@ -22,6 +22,8 @@
<queue-entries>
<queue>
<name>twitter</name>
- <rate>1/m</rate>
+ <!-- poll every 30s, but only allow one request at a time to save CPU -->
+ <rate>2/m</rate>
+ <max-concurrent-requests>1</max-concurrent-requests>
</queue>
</queue-entries>
diff --git a/demos/tweetstore/gae-tweetstore-spring/src/main/webapp/WEB-INF/web.xml b/demos/tweetstore/gae-tweetstore-spring/src/main/webapp/WEB-INF/web.xml
index c6dead1..971ada2 100644
--- a/demos/tweetstore/gae-tweetstore-spring/src/main/webapp/WEB-INF/web.xml
+++ b/demos/tweetstore/gae-tweetstore-spring/src/main/webapp/WEB-INF/web.xml
@@ -41,9 +41,22 @@
<servlet-name>dispatcher</servlet-name>
<url-pattern>/tweets/*</url-pattern>
</servlet-mapping>
-
+ <servlet-mapping>
+ <servlet-name>dispatcher</servlet-name>
+ <url-pattern>/stores/*</url-pattern>
+ </servlet-mapping>
+
+ <!-- limit submission of storage tasks to the cron job -->
+ <security-constraint>
+ <web-resource-collection>
+ <url-pattern>/stores/*</url-pattern>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>admin</role-name>
+ </auth-constraint>
+ </security-constraint>
+
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
-
</web-app>
\ No newline at end of file
diff --git a/demos/tweetstore/gae-tweetstore-spring/src/test/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresControllerTest.java b/demos/tweetstore/gae-tweetstore-spring/src/test/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresControllerTest.java
new file mode 100644
index 0000000..9a6ca29
--- /dev/null
+++ b/demos/tweetstore/gae-tweetstore-spring/src/test/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresControllerTest.java
@@ -0,0 +1,65 @@
+/**
+ * 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.demo.tweetstore.controller;
+
+import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl;
+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 java.util.Map;
+
+import org.jclouds.blobstore.BlobStoreContext;
+import org.jclouds.blobstore.BlobStoreContextFactory;
+import org.testng.annotations.Test;
+
+import com.google.appengine.api.taskqueue.Queue;
+import com.google.appengine.api.taskqueue.TaskOptions.Method;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Tests behavior of {@code StoreTweetsController}
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "unit")
+public class EnqueueStoresControllerTest {
+
+ Map<String, BlobStoreContext> createBlobStores() {
+ Map<String, BlobStoreContext> contexts = ImmutableMap.of(
+ "test1", new BlobStoreContextFactory().createContext("transient", "dummy", "dummy"),
+ "test2", new BlobStoreContextFactory().createContext("transient", "dummy", "dummy"));
+ return contexts;
+ }
+
+ public void testEnqueueStores() {
+ Map<String, BlobStoreContext> stores = createBlobStores();
+ Queue taskQueue = createMock(Queue.class);
+ EnqueueStoresController function = new EnqueueStoresController(stores, taskQueue);
+
+ expect(taskQueue.add(withUrl("/store/do").header("context", "test1").method(Method.GET))).andReturn(null);
+ expect(taskQueue.add(withUrl("/store/do").header("context", "test2").method(Method.GET))).andReturn(null);
+ replay(taskQueue);
+
+ function.enqueueStoreTweetTasks();
+
+ verify(taskQueue);
+ }
+}
diff --git a/demos/tweetstore/gae-tweetstore/src/main/java/org/jclouds/demo/tweetstore/config/GuiceServletConfig.java b/demos/tweetstore/gae-tweetstore/src/main/java/org/jclouds/demo/tweetstore/config/GuiceServletConfig.java
index 19a444b..e321c91 100644
--- a/demos/tweetstore/gae-tweetstore/src/main/java/org/jclouds/demo/tweetstore/config/GuiceServletConfig.java
+++ b/demos/tweetstore/gae-tweetstore/src/main/java/org/jclouds/demo/tweetstore/config/GuiceServletConfig.java
@@ -18,7 +18,6 @@
*/
package org.jclouds.demo.tweetstore.config;
-import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Predicates.in;
@@ -43,6 +42,7 @@
import org.jclouds.blobstore.BlobStoreContextFactory;
import org.jclouds.demo.tweetstore.config.util.CredentialsCollector;
import org.jclouds.demo.tweetstore.controller.AddTweetsController;
+import org.jclouds.demo.tweetstore.controller.EnqueueStoresController;
import org.jclouds.demo.tweetstore.controller.StoreTweetsController;
import org.jclouds.gae.config.GoogleAppEngineConfigurationModule;
@@ -53,7 +53,6 @@
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
-import com.google.appengine.api.taskqueue.TaskOptions.Method;
import com.google.appengine.repackaged.com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
@@ -112,10 +111,6 @@
// get a queue for submitting store tweet requests
queue = QueueFactory.getQueue("twitter");
- // submit a job to store tweets for each configured blobstore
- for (String name : providerTypeToBlobStoreMap.keySet()) {
- queue.add(withUrl("/store/do").header("context", name).method(Method.GET));
- }
super.contextInitialized(servletContextEvent);
}
@@ -151,9 +146,11 @@
bind(new TypeLiteral<Map<String, BlobStoreContext>>() {
}).toInstance(providerTypeToBlobStoreMap);
bind(Twitter.class).toInstance(twitterClient);
+ bind(Queue.class).toInstance(queue);
bindConstant().annotatedWith(Names.named(PROPERTY_TWEETSTORE_CONTAINER)).to(container);
serve("/store/*").with(StoreTweetsController.class);
serve("/tweets/*").with(AddTweetsController.class);
+ serve("/stores/*").with(EnqueueStoresController.class);
}
});
}
diff --git a/demos/tweetstore/gae-tweetstore/src/main/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresController.java b/demos/tweetstore/gae-tweetstore/src/main/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresController.java
new file mode 100644
index 0000000..94568e4
--- /dev/null
+++ b/demos/tweetstore/gae-tweetstore/src/main/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresController.java
@@ -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.demo.tweetstore.controller;
+
+import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl;
+import static com.google.appengine.repackaged.com.google.common.base.Strings.nullToEmpty;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.blobstore.BlobStoreContext;
+import org.jclouds.logging.Logger;
+
+import com.google.appengine.api.taskqueue.Queue;
+import com.google.appengine.api.taskqueue.TaskOptions.Method;
+import com.google.common.annotations.VisibleForTesting;
+
+/**
+ * Adds tasks to retrieve and store tweets in all registered contexts to an async
+ * task queue.
+ *
+ * @author Andrew Phillips
+ * @see StoreTweetsController
+ */
+@Singleton
+public class EnqueueStoresController extends HttpServlet {
+ /** The serialVersionUID */
+ private static final long serialVersionUID = 7215420527854203714L;
+
+ private final Set<String> contextNames;
+ private final Queue taskQueue;
+
+ @Resource
+ protected Logger logger = Logger.NULL;
+
+ @Inject
+ public EnqueueStoresController(Map<String, BlobStoreContext> contexts,
+ Queue taskQueue) {
+ contextNames = contexts.keySet();
+ this.taskQueue = taskQueue;
+ }
+
+ @VisibleForTesting
+ void enqueueStoreTweetTasks() {
+ for (String contextName : contextNames) {
+ logger.debug("enqueuing task to store tweets in blobstore '%s'", contextName);
+ taskQueue.add(withUrl("/store/do").header("context", contextName).method(Method.GET));
+ }
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ if (!nullToEmpty(request.getHeader("X-AppEngine-Cron")).equals("true")) {
+ response.sendError(401);
+ }
+
+ try {
+ enqueueStoreTweetTasks();
+ response.setContentType(MediaType.TEXT_PLAIN);
+ response.getWriter().println("Done!");
+ } catch (Exception e) {
+ logger.error(e, "Error storing tweets");
+ throw new ServletException(e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/demos/tweetstore/gae-tweetstore/src/main/platform/cron.xml b/demos/tweetstore/gae-tweetstore/src/main/platform/cron.xml
new file mode 100644
index 0000000..193a540
--- /dev/null
+++ b/demos/tweetstore/gae-tweetstore/src/main/platform/cron.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+ 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.
+
+-->
+<cronentries>
+ <cron>
+ <url>/stores/do</url>
+ <description>Enqueue 'store tweet' tasks for all contexts</description>
+ <schedule>every 10 minutes</schedule>
+ </cron>
+</cronentries>
\ No newline at end of file
diff --git a/demos/tweetstore/gae-tweetstore/src/main/webapp/WEB-INF/queue.xml b/demos/tweetstore/gae-tweetstore/src/main/webapp/WEB-INF/queue.xml
index e8c42d7..1bc53f3 100644
--- a/demos/tweetstore/gae-tweetstore/src/main/webapp/WEB-INF/queue.xml
+++ b/demos/tweetstore/gae-tweetstore/src/main/webapp/WEB-INF/queue.xml
@@ -22,6 +22,8 @@
<queue-entries>
<queue>
<name>twitter</name>
- <rate>1/m</rate>
+ <!-- poll every 30s, but only allow one request at a time to save CPU -->
+ <rate>2/m</rate>
+ <max-concurrent-requests>1</max-concurrent-requests>
</queue>
</queue-entries>
diff --git a/demos/tweetstore/gae-tweetstore/src/main/webapp/WEB-INF/web.xml b/demos/tweetstore/gae-tweetstore/src/main/webapp/WEB-INF/web.xml
index 11c41f1..d5b17d7 100644
--- a/demos/tweetstore/gae-tweetstore/src/main/webapp/WEB-INF/web.xml
+++ b/demos/tweetstore/gae-tweetstore/src/main/webapp/WEB-INF/web.xml
@@ -39,7 +39,17 @@
<listener-class>org.jclouds.demo.tweetstore.config.GuiceServletConfig
</listener-class>
</listener>
-
+
+ <!-- limit submission of storage tasks to the cron job -->
+ <security-constraint>
+ <web-resource-collection>
+ <url-pattern>/stores/*</url-pattern>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>admin</role-name>
+ </auth-constraint>
+ </security-constraint>
+
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
diff --git a/demos/tweetstore/gae-tweetstore/src/test/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresControllerTest.java b/demos/tweetstore/gae-tweetstore/src/test/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresControllerTest.java
new file mode 100644
index 0000000..9a6ca29
--- /dev/null
+++ b/demos/tweetstore/gae-tweetstore/src/test/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresControllerTest.java
@@ -0,0 +1,65 @@
+/**
+ * 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.demo.tweetstore.controller;
+
+import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl;
+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 java.util.Map;
+
+import org.jclouds.blobstore.BlobStoreContext;
+import org.jclouds.blobstore.BlobStoreContextFactory;
+import org.testng.annotations.Test;
+
+import com.google.appengine.api.taskqueue.Queue;
+import com.google.appengine.api.taskqueue.TaskOptions.Method;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Tests behavior of {@code StoreTweetsController}
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "unit")
+public class EnqueueStoresControllerTest {
+
+ Map<String, BlobStoreContext> createBlobStores() {
+ Map<String, BlobStoreContext> contexts = ImmutableMap.of(
+ "test1", new BlobStoreContextFactory().createContext("transient", "dummy", "dummy"),
+ "test2", new BlobStoreContextFactory().createContext("transient", "dummy", "dummy"));
+ return contexts;
+ }
+
+ public void testEnqueueStores() {
+ Map<String, BlobStoreContext> stores = createBlobStores();
+ Queue taskQueue = createMock(Queue.class);
+ EnqueueStoresController function = new EnqueueStoresController(stores, taskQueue);
+
+ expect(taskQueue.add(withUrl("/store/do").header("context", "test1").method(Method.GET))).andReturn(null);
+ expect(taskQueue.add(withUrl("/store/do").header("context", "test2").method(Method.GET))).andReturn(null);
+ replay(taskQueue);
+
+ function.enqueueStoreTweetTasks();
+
+ verify(taskQueue);
+ }
+}
diff --git a/drivers/apachehc/src/main/java/org/jclouds/http/apachehc/ApacheHCUtils.java b/drivers/apachehc/src/main/java/org/jclouds/http/apachehc/ApacheHCUtils.java
index 15b6f4f..25e84bd 100644
--- a/drivers/apachehc/src/main/java/org/jclouds/http/apachehc/ApacheHCUtils.java
+++ b/drivers/apachehc/src/main/java/org/jclouds/http/apachehc/ApacheHCUtils.java
@@ -43,6 +43,7 @@
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.params.CoreProtocolPNames;
+import org.jclouds.JcloudsVersion;
import org.jclouds.http.HttpRequest;
import org.jclouds.io.Payload;
import org.jclouds.io.payloads.BasePayload;
@@ -59,8 +60,8 @@
*/
@Singleton
public class ApacheHCUtils {
-
- public static final String USER_AGENT = "jclouds/1.0 httpclient/4.0.1";
+ //TODO: look up httpclient version
+ public static final String USER_AGENT = String.format("jclouds/%s httpclient/%s", JcloudsVersion.get(), "4.1.1");
public static HttpUriRequest convertToApacheRequest(HttpRequest request) {
HttpUriRequest apacheRequest;
diff --git a/drivers/gae/src/main/java/org/jclouds/gae/GaeHttpCommandExecutorService.java b/drivers/gae/src/main/java/org/jclouds/gae/GaeHttpCommandExecutorService.java
index 929bafd..2ca19fa 100644
--- a/drivers/gae/src/main/java/org/jclouds/gae/GaeHttpCommandExecutorService.java
+++ b/drivers/gae/src/main/java/org/jclouds/gae/GaeHttpCommandExecutorService.java
@@ -26,6 +26,7 @@
import javax.inject.Singleton;
import org.jclouds.Constants;
+import org.jclouds.JcloudsVersion;
import org.jclouds.concurrent.SingleThreaded;
import org.jclouds.http.HttpCommandExecutorService;
import org.jclouds.http.HttpRequest;
@@ -50,8 +51,9 @@
@SingleThreaded
@Singleton
public class GaeHttpCommandExecutorService extends BaseHttpCommandExecutorService<HTTPRequest> {
- public static final String USER_AGENT = "jclouds/1.0 urlfetch/1.3.5";
-
+ //TODO: look up gae version
+ public static final String USER_AGENT = String.format("jclouds/%s urlfetch/%s", JcloudsVersion.get(), "1.4.3");
+
private final URLFetchService urlFetchService;
private final ConvertToGaeRequest convertToGaeRequest;
private final ConvertToJcloudsResponse convertToJcloudsResponse;
diff --git a/drivers/gae/src/test/java/org/jclouds/gae/AsyncGaeHttpCommandExecutorServiceIntegrationTest.java b/drivers/gae/src/test/java/org/jclouds/gae/AsyncGaeHttpCommandExecutorServiceIntegrationTest.java
index 0d1113c..2971e88 100644
--- a/drivers/gae/src/test/java/org/jclouds/gae/AsyncGaeHttpCommandExecutorServiceIntegrationTest.java
+++ b/drivers/gae/src/test/java/org/jclouds/gae/AsyncGaeHttpCommandExecutorServiceIntegrationTest.java
@@ -63,6 +63,7 @@
*
* @author Adrian Cole
*/
+@Test
public class AsyncGaeHttpCommandExecutorServiceIntegrationTest extends BaseHttpCommandExecutorServiceIntegrationTest {
Logger logger = Logger.CONSOLE;
diff --git a/drivers/sshj/src/main/java/org/jclouds/sshj/SshjSshClient.java b/drivers/sshj/src/main/java/org/jclouds/sshj/SshjSshClient.java
index 9427141..1d55a8c 100644
--- a/drivers/sshj/src/main/java/org/jclouds/sshj/SshjSshClient.java
+++ b/drivers/sshj/src/main/java/org/jclouds/sshj/SshjSshClient.java
@@ -46,6 +46,7 @@
import net.schmizz.sshj.connection.channel.direct.Session;
import net.schmizz.sshj.connection.channel.direct.Session.Command;
import net.schmizz.sshj.sftp.SFTPClient;
+import net.schmizz.sshj.sftp.SFTPException;
import net.schmizz.sshj.transport.TransportException;
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
import net.schmizz.sshj.userauth.UserAuthException;
@@ -122,7 +123,9 @@
// NOTE cannot retry io exceptions, as SSHException is a part of the chain
private Predicate<Throwable> retryPredicate = or(instanceOf(ConnectionException.class),
instanceOf(ConnectException.class), instanceOf(SocketTimeoutException.class),
- instanceOf(TransportException.class));
+ instanceOf(TransportException.class),
+ // safe to retry sftp exceptions as they are idempotent
+ instanceOf(SFTPException.class));
@Resource
@Named("jclouds.ssh")
diff --git a/drivers/sshj/src/test/java/org/jclouds/sshj/SshjSshClientTest.java b/drivers/sshj/src/test/java/org/jclouds/sshj/SshjSshClientTest.java
index 08d4b5e..44a744b 100644
--- a/drivers/sshj/src/test/java/org/jclouds/sshj/SshjSshClientTest.java
+++ b/drivers/sshj/src/test/java/org/jclouds/sshj/SshjSshClientTest.java
@@ -19,11 +19,11 @@
package org.jclouds.sshj;
import static com.google.inject.name.Names.bindProperties;
+import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
-import static org.easymock.classextension.EasyMock.createMock;
-import static org.easymock.classextension.EasyMock.replay;
-import static org.easymock.classextension.EasyMock.verify;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
import java.io.IOException;
import java.net.ConnectException;
@@ -34,6 +34,7 @@
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.common.SSHException;
import net.schmizz.sshj.connection.ConnectionException;
+import net.schmizz.sshj.sftp.SFTPException;
import net.schmizz.sshj.transport.TransportException;
import net.schmizz.sshj.userauth.UserAuthException;
@@ -99,6 +100,7 @@
public void testExceptionClassesRetry() {
assert ssh.shouldRetry(new ConnectionException("Read timed out", new SSHException("Read timed out",
new SocketTimeoutException("Read timed out"))));
+ assert ssh.shouldRetry(new SFTPException("Failure!"));
assert ssh.shouldRetry(new SocketTimeoutException("connect timed out"));
assert ssh.shouldRetry(new TransportException("socket closed"));
assert ssh.shouldRetry(new ConnectionException("problem"));
diff --git a/project/pom.xml b/project/pom.xml
index bf7f149..467a5fe 100644
--- a/project/pom.xml
+++ b/project/pom.xml
@@ -194,7 +194,7 @@
<maven.site.url.base>gitsite:git@github.com/jclouds/jclouds-maven-site.git</maven.site.url.base>
<http.proxyHost />
<http.proxyPort />
- <jclouds.wire.httpstream.url>http://apache.opensourceresources.org/commons/logging/binaries/commons-logging-1.1.1-bin.tar.gz</jclouds.wire.httpstream.url>
+ <jclouds.wire.httpstream.url>http://apache.deathculture.net//commons/logging/binaries/commons-logging-1.1.1-bin.tar.gz</jclouds.wire.httpstream.url>
<jclouds.wire.httpstream.md5>e5de09672af9b386c30a311654d8541a</jclouds.wire.httpstream.md5>
<jclouds.blobstore.httpstream.url>${jclouds.wire.httpstream.url}</jclouds.blobstore.httpstream.url>
<jclouds.blobstore.httpstream.md5>${jclouds.wire.httpstream.md5}</jclouds.blobstore.httpstream.md5>
@@ -225,13 +225,13 @@
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
- <version>6.0.1</version>
+ <version>6.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymockclassextension</artifactId>
- <version>2.4</version>
+ <version>3.1</version>
<scope>test</scope>
</dependency>
<dependency>
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/AWSAMIClientLiveTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/AWSAMIClientLiveTest.java
index ebeeb4c..630b2d5 100644
--- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/AWSAMIClientLiveTest.java
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/AWSAMIClientLiveTest.java
@@ -190,14 +190,14 @@
// TODO client.resetLaunchPermissionsOnImageInRegion(null, imageId);
}
- @Test(expectedExceptions = AuthorizationException.class)
+ @Test(enabled = false)
public void testGetLaunchPermissionForImage() {
- System.out.println(client.getLaunchPermissionForImageInRegion(null, imageId));
+ // TODO System.out.println(client.getLaunchPermissionForImageInRegion(null, imageId));
}
- @Test(expectedExceptions = AuthorizationException.class)
+ @Test(enabled = false)
public void testGetProductCodesForImage() {
- System.out.println(client.getProductCodesForImageInRegion(null, imageId));
+ // TODO System.out.println(client.getProductCodesForImageInRegion(null, imageId));
}
@Test(enabled = false)
diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/AWSS3AsyncClient.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/AWSS3AsyncClient.java
index 53669f9..fc19334 100644
--- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/AWSS3AsyncClient.java
+++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/AWSS3AsyncClient.java
@@ -22,6 +22,7 @@
import java.util.Map;
+import org.jclouds.aws.s3.blobstore.options.AWSS3PutObjectOptions;
import org.jclouds.javax.annotation.Nullable;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
@@ -54,9 +55,12 @@
import org.jclouds.s3.S3AsyncClient;
import org.jclouds.s3.S3Client;
import org.jclouds.s3.binders.BindAsHostPrefixIfConfigured;
+import org.jclouds.s3.binders.BindS3ObjectMetadataToRequest;
import org.jclouds.s3.domain.ObjectMetadata;
+import org.jclouds.s3.domain.S3Object;
import org.jclouds.s3.filters.RequestAuthorizeSignature;
import org.jclouds.s3.functions.BindRegionToXmlPayload;
+import org.jclouds.s3.functions.ObjectKey;
import org.jclouds.s3.functions.ReturnFalseIfBucketAlreadyOwnedByYouOrIllegalState;
import org.jclouds.s3.options.PutBucketOptions;
import org.jclouds.s3.options.PutObjectOptions;
@@ -74,6 +78,7 @@
@RequestFilters(RequestAuthorizeSignature.class)
@BlobScope(CONTAINER)
public interface AWSS3AsyncClient extends S3AsyncClient {
+
/**
* @see S3Client#putBucketInRegion
*/
diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/AWSS3Client.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/AWSS3Client.java
index 5ed08d9..11decd9 100644
--- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/AWSS3Client.java
+++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/AWSS3Client.java
@@ -21,30 +21,33 @@
import java.util.Map;
import java.util.concurrent.TimeUnit;
+import org.jclouds.aws.s3.blobstore.options.AWSS3PutObjectOptions;
import org.jclouds.concurrent.Timeout;
import org.jclouds.io.Payload;
import org.jclouds.s3.S3Client;
import org.jclouds.s3.domain.ObjectMetadata;
+import org.jclouds.s3.domain.S3Object;
import org.jclouds.s3.options.PutObjectOptions;
/**
* Provides access to amazon-specific S3 features
- *
+ *
* @author Adrian Cole
* @see AWSS3AsyncClient
*/
@Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
public interface AWSS3Client extends S3Client {
+
/**
* This operation initiates a multipart upload and returns an upload ID. This upload ID is used
* to associate all the parts in the specific multipart upload. You specify this upload ID in
* each of your subsequent upload part requests (see Upload Part). You also include this upload
* ID in the final request to either complete or abort the multipart upload request.
- *
+ *
* <h4>Note</h4> If you create an object using the multipart upload APIs, currently you cannot
* copy the object between regions.
- *
- *
+ *
+ *
* @param bucketName
* namespace of the object you are to upload
* @param objectMetadata
@@ -61,8 +64,8 @@
* parts will be freed. However, if any part uploads are currently in progress, those part
* uploads might or might not succeed. As a result, it might be necessary to abort a given
* multipart upload multiple times in order to completely free all storage consumed by all parts.
- *
- *
+ *
+ *
* @param bucketName
* namespace of the object you are deleting
* @param key
@@ -77,20 +80,20 @@
* Initiate Multipart Upload) before you can upload any part. In response to your initiate
* request. Amazon S3 returns an upload ID, a unique identifier, that you must include in your
* upload part request.
- *
+ *
* <p/>
* Part numbers can be any number from 1 to 10,000, inclusive. A part number uniquely identifies
* a part and also defines its position within the object being created. If you upload a new part
* using the same part number that was used with a previous part, the previously uploaded part is
* overwritten. Each part must be at least 5 MB in size, except the last part. There is no size
* limit on the last part of your multipart upload.
- *
+ *
* <p/>
* To ensure that data is not corrupted when traversing the network, specify the Content-MD5
* header in the upload part request. Amazon S3 checks the part data against the provided MD5
* value. If they do not match, Amazon S3 returns an error.
- *
- *
+ *
+ *
* @param bucketName
* namespace of the object you are storing
* @param key
@@ -109,7 +112,7 @@
String uploadPart(String bucketName, String key, int partNumber, String uploadId, Payload part);
/**
- *
+ *
This operation completes a multipart upload by assembling previously uploaded parts.
* <p/>
* You first initiate the multipart upload and then upload all parts using the Upload Parts
@@ -129,7 +132,7 @@
* <p/>
* Note that if Complete Multipart Upload fails, applications should be prepared to retry the
* failed requests.
- *
+ *
* @param bucketName
* namespace of the object you are deleting
* @param key
diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/AWSS3AsyncBlobStore.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/AWSS3AsyncBlobStore.java
index 38848d6..02d7231 100644
--- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/AWSS3AsyncBlobStore.java
+++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/AWSS3AsyncBlobStore.java
@@ -25,9 +25,12 @@
import javax.inject.Named;
import javax.inject.Provider;
+import com.google.common.cache.CacheLoader;
import org.jclouds.Constants;
import org.jclouds.aws.s3.AWSS3AsyncClient;
import org.jclouds.aws.s3.AWSS3Client;
+import org.jclouds.aws.s3.blobstore.options.AWSS3PutObjectOptions;
+import org.jclouds.aws.s3.blobstore.options.AWSS3PutOptions;
import org.jclouds.aws.s3.blobstore.strategy.AsyncMultipartUploadStrategy;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.domain.Blob;
@@ -37,6 +40,8 @@
import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.collect.Memoized;
import org.jclouds.domain.Location;
+import org.jclouds.s3.S3AsyncClient;
+import org.jclouds.s3.S3Client;
import org.jclouds.s3.blobstore.S3AsyncBlobStore;
import org.jclouds.s3.blobstore.functions.BlobToObject;
import org.jclouds.s3.blobstore.functions.BucketToResourceList;
@@ -49,14 +54,20 @@
import com.google.common.base.Supplier;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.ListenableFuture;
+import org.jclouds.s3.domain.CannedAccessPolicy;
+import org.jclouds.s3.domain.ObjectMetadata;
+
+import static org.jclouds.s3.domain.ObjectMetadata.StorageClass.REDUCED_REDUNDANCY;
/**
- *
- * @author Tibor Kiss
+ *
+ * @author Tibor Kiss, Andrei Savu
*/
public class AWSS3AsyncBlobStore extends S3AsyncBlobStore {
private final Provider<AsyncMultipartUploadStrategy> multipartUploadStrategy;
+ private final LoadingCache<String, AccessControlList> bucketAcls;
+ private final BlobToObject blob2Object;
@Inject
public AWSS3AsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils,
@@ -71,12 +82,39 @@
container2BucketListOptions, bucket2ResourceList, object2Blob, blob2ObjectGetOptions, blob2Object,
object2BlobMd, fetchBlobMetadataProvider, bucketAcls);
this.multipartUploadStrategy = multipartUploadStrategy;
+ this.bucketAcls = bucketAcls;
+ this.blob2Object = blob2Object;
}
@Override
public ListenableFuture<String> putBlob(String container, Blob blob, PutOptions options) {
- // need to use a provider if the strategy object is stateful
- return multipartUploadStrategy.get().execute(container, blob);
+ if (options.isMultipart()) {
+ // need to use a provider if the strategy object is stateful
+ return multipartUploadStrategy.get().execute(container, blob, options);
+ } else if (options instanceof AWSS3PutOptions &&
+ ((AWSS3PutOptions) options).getStorageClass() == REDUCED_REDUNDANCY) {
+ return putBlobWithReducedRedundancy(container, blob);
+
+ } else {
+ return super.putBlob(container, blob, options);
+ }
+ }
+
+ private ListenableFuture<String> putBlobWithReducedRedundancy(String container, Blob blob) {
+ AWSS3PutObjectOptions options = new AWSS3PutObjectOptions();
+ try {
+ AccessControlList acl = bucketAcls.getUnchecked(container);
+ if (acl != null && acl.hasPermission(AccessControlList.GroupGranteeURI.ALL_USERS,
+ AccessControlList.Permission.READ)) {
+ options.withAcl(CannedAccessPolicy.PUBLIC_READ);
+ }
+ options.storageClass(ObjectMetadata.StorageClass.REDUCED_REDUNDANCY);
+
+ } catch (CacheLoader.InvalidCacheLoadException e) {
+ // nulls not permitted from cache loader
+ }
+ return S3AsyncClient.class.cast(getContext().getProviderSpecificContext().getApi())
+ .putObject(container, blob2Object.apply(blob), options);
}
}
diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/AWSS3BlobStore.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/AWSS3BlobStore.java
index 8bb382d..f981c3c 100644
--- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/AWSS3BlobStore.java
+++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/AWSS3BlobStore.java
@@ -23,7 +23,10 @@
import javax.inject.Inject;
import javax.inject.Provider;
+import com.google.common.cache.CacheLoader;
import org.jclouds.aws.s3.AWSS3Client;
+import org.jclouds.aws.s3.blobstore.options.AWSS3PutObjectOptions;
+import org.jclouds.aws.s3.blobstore.options.AWSS3PutOptions;
import org.jclouds.aws.s3.blobstore.strategy.MultipartUploadStrategy;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.domain.Blob;
@@ -33,6 +36,7 @@
import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.collect.Memoized;
import org.jclouds.domain.Location;
+import org.jclouds.s3.S3Client;
import org.jclouds.s3.blobstore.S3BlobStore;
import org.jclouds.s3.blobstore.functions.BlobToObject;
import org.jclouds.s3.blobstore.functions.BucketToResourceList;
@@ -44,15 +48,22 @@
import com.google.common.base.Supplier;
import com.google.common.cache.LoadingCache;
+import org.jclouds.s3.domain.CannedAccessPolicy;
+import org.jclouds.s3.domain.ObjectMetadata;
+import org.jclouds.s3.options.PutObjectOptions;
+
+import static org.jclouds.s3.domain.ObjectMetadata.StorageClass.REDUCED_REDUNDANCY;
/**
- * Proived AWS S3 specific extensions.
- *
- * @author Tibor Kiss
+ * Provide AWS S3 specific extensions.
+ *
+ * @author Tibor Kiss, Andrei Savu
*/
public class AWSS3BlobStore extends S3BlobStore {
private final Provider<MultipartUploadStrategy> multipartUploadStrategy;
+ private final LoadingCache<String, AccessControlList> bucketAcls;
+ private final BlobToObject blob2Object;
@Inject
AWSS3BlobStore(BlobStoreContext context, BlobUtils blobUtils, Supplier<Location> defaultLocation,
@@ -66,11 +77,39 @@
bucket2ResourceList, object2Blob, blob2ObjectGetOptions, blob2Object, object2BlobMd,
fetchBlobMetadataProvider, bucketAcls);
this.multipartUploadStrategy = multipartUploadStrategy;
+ this.bucketAcls = bucketAcls;
+ this.blob2Object = blob2Object;
}
@Override
public String putBlob(String container, Blob blob, PutOptions options) {
- // need to use a provider if the strategy object is stateful
- return multipartUploadStrategy.get().execute(container, blob);
+ if (options.isMultipart()) {
+ // need to use a provider if the strategy object is stateful
+ return multipartUploadStrategy.get().execute(container, blob, options);
+
+ } else if ((options instanceof AWSS3PutOptions) &&
+ (((AWSS3PutOptions) options).getStorageClass() == REDUCED_REDUNDANCY)) {
+ return putBlobWithReducedRedundancy(container, blob);
+
+ } else {
+ return super.putBlob(container, blob, options);
+ }
+ }
+
+ private String putBlobWithReducedRedundancy(String container, Blob blob) {
+ AWSS3PutObjectOptions options = new AWSS3PutObjectOptions();
+ try {
+ AccessControlList acl = bucketAcls.getUnchecked(container);
+ if (acl != null && acl.hasPermission(AccessControlList.GroupGranteeURI.ALL_USERS,
+ AccessControlList.Permission.READ)) {
+ options.withAcl(CannedAccessPolicy.PUBLIC_READ);
+ }
+ options.storageClass(ObjectMetadata.StorageClass.REDUCED_REDUNDANCY);
+
+ } catch (CacheLoader.InvalidCacheLoadException e) {
+ // nulls not permitted from cache loader
+ }
+ return S3Client.class.cast(getContext().getProviderSpecificContext().getApi())
+ .putObject(container, blob2Object.apply(blob), options);
}
}
diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/config/AWSS3BlobStoreContextModule.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/config/AWSS3BlobStoreContextModule.java
index 71c85e2..89db158 100644
--- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/config/AWSS3BlobStoreContextModule.java
+++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/config/AWSS3BlobStoreContextModule.java
@@ -28,6 +28,7 @@
import org.jclouds.aws.s3.blobstore.strategy.internal.SequentialMultipartUploadStrategy;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.internal.BlobStoreContextImpl;
+import org.jclouds.blobstore.options.PutOptions;
import org.jclouds.s3.blobstore.S3AsyncBlobStore;
import org.jclouds.s3.blobstore.S3BlobStore;
import org.jclouds.s3.blobstore.config.S3BlobStoreContextModule;
diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/options/AWSS3PutObjectOptions.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/options/AWSS3PutObjectOptions.java
new file mode 100644
index 0000000..eadf938
--- /dev/null
+++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/options/AWSS3PutObjectOptions.java
@@ -0,0 +1,71 @@
+/**
+ * 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.aws.s3.blobstore.options;
+
+import org.jclouds.s3.domain.CannedAccessPolicy;
+import org.jclouds.s3.domain.ObjectMetadata;
+import org.jclouds.s3.options.PutObjectOptions;
+import org.jclouds.s3.reference.S3Headers;
+
+/**
+ * Contains options supported in the AWS S3 REST API for the PUT object operation
+ *
+ * @see PutObjectOptions
+ * @author Andrei Savu
+ */
+public class AWSS3PutObjectOptions extends PutObjectOptions {
+
+ public static class Builder {
+
+ /**
+ * @see AWSS3PutObjectOptions#storageClass
+ */
+ public static AWSS3PutObjectOptions storageClass(ObjectMetadata.StorageClass storageClass) {
+ AWSS3PutObjectOptions options = new AWSS3PutObjectOptions();
+ return options.storageClass(storageClass);
+ }
+
+ /**
+ * @see AWSS3PutObjectOptions#withAcl
+ */
+ public static AWSS3PutObjectOptions withAcl(CannedAccessPolicy acl) {
+ AWSS3PutObjectOptions options = new AWSS3PutObjectOptions();
+ return options.withAcl(acl);
+ }
+ }
+
+ private ObjectMetadata.StorageClass storageClass = ObjectMetadata.StorageClass.STANDARD;
+
+ public AWSS3PutObjectOptions storageClass(ObjectMetadata.StorageClass storageClass) {
+ this.storageClass = storageClass;
+ if (storageClass != ObjectMetadata.StorageClass.STANDARD) {
+ this.replaceHeader(S3Headers.STORAGE_CLASS, this.storageClass.toString());
+ }
+ return this;
+ }
+
+ public ObjectMetadata.StorageClass getStorageClass() {
+ return storageClass;
+ }
+
+ @Override
+ public AWSS3PutObjectOptions withAcl(CannedAccessPolicy acl) {
+ return (AWSS3PutObjectOptions) super.withAcl(acl);
+ }
+}
diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/options/AWSS3PutOptions.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/options/AWSS3PutOptions.java
new file mode 100644
index 0000000..e67f4a1
--- /dev/null
+++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/options/AWSS3PutOptions.java
@@ -0,0 +1,80 @@
+/**
+ * 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.aws.s3.blobstore.options;
+
+import org.jclouds.blobstore.options.PutOptions;
+import org.jclouds.s3.domain.ObjectMetadata;
+
+/**
+ * Contains AWS-S3 specific options supported in the put blob operation
+ *
+ * @author Andrei Savu
+ */
+public class AWSS3PutOptions extends PutOptions {
+
+ public static class Builder {
+
+ /**
+ * @see AWSS3PutOptions#multipart()
+ */
+ public static AWSS3PutOptions multipart() {
+ AWSS3PutOptions options = new AWSS3PutOptions();
+ return (AWSS3PutOptions) options.multipart();
+ }
+
+ /**
+ * @see AWSS3PutOptions#storageClass
+ */
+ public static AWSS3PutOptions storageClass(ObjectMetadata.StorageClass storageClass) {
+ AWSS3PutOptions options = new AWSS3PutOptions();
+ return options.storageClass(storageClass);
+ }
+ }
+
+ private ObjectMetadata.StorageClass storageClass;
+
+ public AWSS3PutOptions() {
+ storageClass = ObjectMetadata.StorageClass.STANDARD;
+ }
+
+ public AWSS3PutOptions(boolean multipart, ObjectMetadata.StorageClass storageClass) {
+ super(multipart);
+ this.storageClass = storageClass;
+ }
+
+ public AWSS3PutOptions storageClass(ObjectMetadata.StorageClass storageClass) {
+ this.storageClass = storageClass;
+ return this;
+ }
+
+ public ObjectMetadata.StorageClass getStorageClass() {
+ return storageClass;
+ }
+
+ @Override
+ public AWSS3PutOptions clone() {
+ return new AWSS3PutOptions(isMultipart(), storageClass);
+ }
+
+ @Override
+ public String toString() {
+ return "[multipart=" + isMultipart() +
+ " storageClass=" + storageClass + "]";
+ }
+}
diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/AsyncMultipartUploadStrategy.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/AsyncMultipartUploadStrategy.java
index ccb165e..2d199a2 100644
--- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/AsyncMultipartUploadStrategy.java
+++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/AsyncMultipartUploadStrategy.java
@@ -23,6 +23,7 @@
import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.ImplementedBy;
+import org.jclouds.blobstore.options.PutOptions;
/**
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?qfacts.html"
@@ -32,6 +33,6 @@
@ImplementedBy(ParallelMultipartUploadStrategy.class)
public interface AsyncMultipartUploadStrategy extends MultipartUpload {
- ListenableFuture<String> execute(String container, Blob blob);
+ ListenableFuture<String> execute(String container, Blob blob, PutOptions options);
}
diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/MultipartUploadStrategy.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/MultipartUploadStrategy.java
index e3cf3dd..0d60d19 100644
--- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/MultipartUploadStrategy.java
+++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/MultipartUploadStrategy.java
@@ -22,6 +22,7 @@
import org.jclouds.blobstore.domain.Blob;
import com.google.inject.ImplementedBy;
+import org.jclouds.blobstore.options.PutOptions;
/**
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?qfacts.html"
@@ -31,5 +32,5 @@
@ImplementedBy(SequentialMultipartUploadStrategy.class)
public interface MultipartUploadStrategy extends MultipartUpload {
- String execute(String container, Blob blob);
+ String execute(String container, Blob blob, PutOptions options);
}
diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/internal/ParallelMultipartUploadStrategy.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/internal/ParallelMultipartUploadStrategy.java
index a48b04d..fdfbcfc 100644
--- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/internal/ParallelMultipartUploadStrategy.java
+++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/internal/ParallelMultipartUploadStrategy.java
@@ -45,6 +45,7 @@
import org.jclouds.aws.s3.blobstore.strategy.AsyncMultipartUploadStrategy;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.internal.BlobRuntimeException;
+import org.jclouds.blobstore.options.PutOptions;
import org.jclouds.blobstore.reference.BlobStoreConstants;
import org.jclouds.concurrent.Futures;
import org.jclouds.io.Payload;
@@ -153,7 +154,7 @@
}
@Override
- public ListenableFuture<String> execute(final String container, final Blob blob) {
+ public ListenableFuture<String> execute(final String container, final Blob blob, final PutOptions options) {
return Futures.makeListenable(
ioWorkerExecutor.submit(new Callable<String>() {
@Override
@@ -240,7 +241,7 @@
throw rtex;
}
} else {
- ListenableFuture<String> futureETag = ablobstore.putBlob(container, blob);
+ ListenableFuture<String> futureETag = ablobstore.putBlob(container, blob, options);
return maxTime != null ?
futureETag.get(maxTime,TimeUnit.SECONDS) : futureETag.get();
}
diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/internal/SequentialMultipartUploadStrategy.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/internal/SequentialMultipartUploadStrategy.java
index 51078ae..e4ffc25 100644
--- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/internal/SequentialMultipartUploadStrategy.java
+++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/internal/SequentialMultipartUploadStrategy.java
@@ -31,6 +31,7 @@
import org.jclouds.aws.s3.blobstore.strategy.MultipartUploadStrategy;
import org.jclouds.blobstore.KeyNotFoundException;
import org.jclouds.blobstore.domain.Blob;
+import org.jclouds.blobstore.options.PutOptions;
import org.jclouds.blobstore.reference.BlobStoreConstants;
import org.jclouds.io.Payload;
import org.jclouds.io.PayloadSlicer;
@@ -88,7 +89,7 @@
}
@Override
- public String execute(String container, Blob blob) {
+ public String execute(String container, Blob blob, PutOptions options) {
String key = blob.getMetadata().getName();
Payload payload = blob.getPayload();
MultipartUploadSlicingAlgorithm algorithm = new MultipartUploadSlicingAlgorithm();
@@ -125,7 +126,8 @@
throw rtex;
}
} else {
- return ablobstore.putBlob(container, blob);
+ // TODO: find a way to disable multipart. if we pass the original options, it goes into a stack overflow
+ return ablobstore.putBlob(container, blob, PutOptions.NONE);
}
}
}
diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/config/AWSS3RestClientModule.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/config/AWSS3RestClientModule.java
index 138c301..ccaf4b0 100644
--- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/config/AWSS3RestClientModule.java
+++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/config/AWSS3RestClientModule.java
@@ -33,6 +33,7 @@
import org.jclouds.http.RequiresHttp;
import org.jclouds.location.Region;
import org.jclouds.rest.ConfiguresRestClient;
+import org.jclouds.rest.RestContext;
import org.jclouds.s3.Bucket;
import org.jclouds.s3.S3AsyncClient;
import org.jclouds.s3.S3Client;
@@ -43,7 +44,7 @@
/**
* Configures the S3 connection.
- *
+ *
* @author Adrian Cole
*/
@RequiresHttp
@@ -84,4 +85,15 @@
return in;
}
+ /**
+ * so that we can inject RestContext<S3Client, S3AsyncClient>
+ */
+ @SuppressWarnings("unchecked")
+ @Singleton
+ @Provides
+ RestContext<S3Client, S3AsyncClient>
+ provideBaseContext(RestContext<AWSS3Client, AWSS3AsyncClient> in) {
+ return (RestContext) in;
+ }
+
}
diff --git a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientExpectTest.java b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientExpectTest.java
new file mode 100644
index 0000000..63055cb
--- /dev/null
+++ b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientExpectTest.java
@@ -0,0 +1,77 @@
+/**
+ * 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.aws.s3;
+
+import com.google.common.collect.ImmutableMultimap;
+import org.jclouds.aws.s3.internal.BaseAWSS3ClientExpectTest;
+import org.jclouds.blobstore.domain.Blob;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.io.payloads.StringPayload;
+import org.jclouds.s3.blobstore.functions.BlobToObject;
+import org.testng.annotations.Test;
+
+import java.net.URI;
+
+import static org.jclouds.aws.s3.blobstore.options.AWSS3PutObjectOptions.Builder.storageClass;
+import static org.jclouds.s3.domain.ObjectMetadata.StorageClass;
+
+/**
+ * @author Andrei Savu
+ */
+@Test
+public class AWSS3ClientExpectTest extends BaseAWSS3ClientExpectTest {
+
+ @Test
+ public void testPutWithReducedRedundancy() {
+ AWSS3Client client = requestSendsResponse(
+ HttpRequest.builder()
+ .method("PUT")
+ .endpoint(URI.create("https://test.s3.amazonaws.com/test"))
+ .headers(ImmutableMultimap.of(
+ "x-amz-storage-class", "REDUCED_REDUNDANCY",
+ "Host", "test.s3.amazonaws.com",
+ "Date", CONSTANT_DATE,
+ "Authorization", "AWS identity:1mJrW85/mqZpYTFIK5Ebtt2MM6E="
+ ))
+ .payload(new StringPayload("content"))
+ .build(),
+ HttpResponse.builder()
+ .statusCode(200)
+ .headers(ImmutableMultimap.of(
+ "x-amz-id-2", "w0rL+9fALQiCOToesVQefs8WalIgn+ZhMD7hHMKYud/xv7MyKkAWQOtFNEfK97Ri",
+ "x-amz-request-id", "7A84C3CD4437A4C0",
+ "Date", CONSTANT_DATE,
+ "ETag", "437b930db84b8079c2dd804a71936b5f",
+ "Server", "AmazonS3"
+ ))
+ .build()
+ );
+
+ Blob blob = blobStore.blobBuilder("test").payload("content").build();
+ BlobToObject blobToObject = getInstance(BlobToObject.class);
+
+ client.putObject("test", blobToObject.apply(blob),
+ storageClass(StorageClass.REDUCED_REDUNDANCY));
+ }
+
+ public <T> T getInstance(Class<T> klass) {
+ return blobStoreContext.utils().injector().getInstance(klass);
+ }
+}
diff --git a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java
index e936172..bebe9c9 100644
--- a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java
+++ b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java
@@ -21,8 +21,10 @@
import static com.google.common.io.ByteStreams.join;
import static com.google.common.io.ByteStreams.newInputStreamSupplier;
import static com.google.common.io.ByteStreams.toByteArray;
+import static org.jclouds.aws.s3.blobstore.options.AWSS3PutOptions.Builder.storageClass;
import static org.jclouds.crypto.CryptoStreams.md5;
import static org.jclouds.io.Payloads.newByteArrayPayload;
+import static org.jclouds.s3.options.ListBucketOptions.Builder.withPrefix;
import static org.testng.Assert.assertEquals;
import java.io.ByteArrayInputStream;
@@ -39,9 +41,13 @@
import org.jclouds.http.BaseJettyTest;
import org.jclouds.http.apachehc.config.ApacheHCHttpCommandExecutorServiceModule;
import org.jclouds.io.Payload;
+import org.jclouds.s3.S3Client;
import org.jclouds.s3.S3ClientLiveTest;
+import org.jclouds.s3.domain.ListBucketResponse;
+import org.jclouds.s3.domain.ObjectMetadata;
import org.jclouds.s3.domain.ObjectMetadataBuilder;
import org.jclouds.s3.domain.S3Object;
+import org.jclouds.s3.domain.ObjectMetadata.StorageClass;
import org.testng.ITestContext;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@@ -154,6 +160,29 @@
Blob blob = blobStore.blobBuilder("const.txt")
.payload(new File("target/const.txt")).build();
blobStore.putBlob(containerName, blob, PutOptions.Builder.multipart());
+
+ } finally {
+ returnContainer(containerName);
+ }
+ }
+
+ public void testPutWithReducedRedundancyStorage() throws InterruptedException {
+ String containerName = getContainerName();
+ try {
+ String blobName = "test-rrs";
+ BlobStore blobStore = context.getBlobStore();
+ blobStore.createContainerInLocation(null, containerName);
+
+ Blob blob = blobStore.blobBuilder(blobName).payload("something").build();
+ blobStore.putBlob(containerName, blob,
+ storageClass(StorageClass.REDUCED_REDUNDANCY));
+
+ S3Client s3Client = S3Client.class.cast(context.getProviderSpecificContext().getApi());
+ ListBucketResponse response = s3Client.listBucket(containerName, withPrefix(blobName));
+
+ ObjectMetadata metadata = response.iterator().next();
+ assertEquals(metadata.getStorageClass(), StorageClass.REDUCED_REDUNDANCY);
+
} finally {
returnContainer(containerName);
}
diff --git a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/blobstore/strategy/internal/SequentialMultipartUploadStrategyTest.java b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/blobstore/strategy/internal/SequentialMultipartUploadStrategyTest.java
index a3ddb05..78a4cc6 100644
--- a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/blobstore/strategy/internal/SequentialMultipartUploadStrategyTest.java
+++ b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/blobstore/strategy/internal/SequentialMultipartUploadStrategyTest.java
@@ -33,6 +33,7 @@
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.MutableBlobMetadata;
+import org.jclouds.blobstore.options.PutOptions;
import org.jclouds.io.MutableContentMetadata;
import org.jclouds.io.Payload;
import org.jclouds.io.PayloadSlicer;
@@ -102,7 +103,7 @@
replay(ometa);
SequentialMultipartUploadStrategy strategy = new SequentialMultipartUploadStrategy(ablobStore, slicer);
- strategy.execute(container, blob);
+ strategy.execute(container, blob, PutOptions.NONE);
verify(ablobStore);
verify(slicer);
@@ -167,7 +168,7 @@
SequentialMultipartUploadStrategy strategy = new SequentialMultipartUploadStrategy(ablobStore, slicer);
try {
- strategy.execute(container, blob);
+ strategy.execute(container, blob, PutOptions.NONE);
fail("Should throw RuntimeException with TimeoutException cause!");
} catch (RuntimeException rtex) {
TimeoutException timeout = Throwables2.getFirstThrowableOfType(rtex, TimeoutException.class);
diff --git a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/internal/BaseAWSS3ClientExpectTest.java b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/internal/BaseAWSS3ClientExpectTest.java
new file mode 100644
index 0000000..169b5d5
--- /dev/null
+++ b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/internal/BaseAWSS3ClientExpectTest.java
@@ -0,0 +1,83 @@
+/**
+ * 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.aws.s3.internal;
+
+import com.google.common.base.Function;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+import org.jclouds.aws.s3.AWSS3Client;
+import org.jclouds.aws.s3.config.AWSS3RestClientModule;
+import org.jclouds.blobstore.BlobStore;
+import org.jclouds.blobstore.BlobStoreContext;
+import org.jclouds.blobstore.BlobStoreContextFactory;
+import org.jclouds.date.TimeStamp;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.RequiresHttp;
+import org.jclouds.logging.config.NullLoggingModule;
+import org.jclouds.rest.BaseRestClientExpectTest;
+import org.jclouds.rest.ConfiguresRestClient;
+
+import java.util.Properties;
+
+/**
+ * Base class for writing Expect tests for AWS-S3
+ *
+ * @author Andrei Savu
+ */
+public class BaseAWSS3ClientExpectTest extends BaseRestClientExpectTest<AWSS3Client> {
+
+ protected static final String CONSTANT_DATE = "2009-11-08T15:54:08.897Z";
+
+ protected BlobStoreContext blobStoreContext;
+ protected BlobStore blobStore;
+
+ public BaseAWSS3ClientExpectTest() {
+ provider = "aws-s3";
+ }
+
+ @RequiresHttp
+ @ConfiguresRestClient
+ private static final class TestAWSS3RestClientModule extends AWSS3RestClientModule {
+ @Override
+ protected String provideTimeStamp(@TimeStamp Supplier<String> cache) {
+ return CONSTANT_DATE;
+ }
+ }
+
+ @Override
+ protected Module createModule() {
+ return new TestAWSS3RestClientModule();
+ }
+
+ @Override
+ public AWSS3Client createClient(Function<HttpRequest, HttpResponse> fn, Module module, Properties props) {
+ return clientFrom(BlobStoreContext.class.cast(new BlobStoreContextFactory(setupRestProperties())
+ .createContext(provider, "identity", "credential", ImmutableSet.<Module>of(new ExpectModule(fn),
+ new NullLoggingModule(), module), props)));
+ }
+
+ protected AWSS3Client clientFrom(BlobStoreContext context) {
+ blobStoreContext = context;
+ blobStore = context.getBlobStore();
+ return AWSS3Client.class.cast(context.getProviderSpecificContext().getApi());
+ }
+
+}
diff --git a/providers/azureblob/src/test/java/org/jclouds/azureblob/AzureBlobClientLiveTest.java b/providers/azureblob/src/test/java/org/jclouds/azureblob/AzureBlobClientLiveTest.java
index 22ecdfc..dc84cf6 100644
--- a/providers/azureblob/src/test/java/org/jclouds/azureblob/AzureBlobClientLiveTest.java
+++ b/providers/azureblob/src/test/java/org/jclouds/azureblob/AzureBlobClientLiveTest.java
@@ -50,6 +50,7 @@
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.rest.BaseRestClientLiveTest;
import org.jclouds.util.Strings2;
+import org.jclouds.util.Throwables2;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
@@ -320,8 +321,9 @@
client.getBlob(privateContainer, object.getProperties().getName(), GetOptions.Builder
.ifETagDoesntMatch(newEtag));
} catch (Exception e) {
- assertEquals(e.getCause().getClass(), HttpResponseException.class);
- assertEquals(((HttpResponseException) e.getCause()).getResponse().getStatusCode(), 304);
+ HttpResponseException httpEx = Throwables2.getFirstThrowableOfType(e, HttpResponseException.class);
+ assert (httpEx != null) : "expected http exception, not " + e;
+ assertEquals(httpEx.getResponse().getStatusCode(), 304);
}
// Matching ETag TODO this shouldn't fail!!!
diff --git a/providers/bluelock-vcloud-zone01/pom.xml b/providers/bluelock-vcloud-zone01/pom.xml
index b3642be..1ecd381 100644
--- a/providers/bluelock-vcloud-zone01/pom.xml
+++ b/providers/bluelock-vcloud-zone01/pom.xml
@@ -36,7 +36,7 @@
<properties>
<test.bluelock-vcloud-zone01.endpoint>https://zone01.bluelock.com/api</test.bluelock-vcloud-zone01.endpoint>
<test.bluelock-vcloud-zone01.api-version>1.0</test.bluelock-vcloud-zone01.api-version>
- <test.bluelock-vcloud-zone01.build-version />
+ <test.bluelock-vcloud-zone01.build-version>1.0.0.285979</test.bluelock-vcloud-zone01.build-version>
<test.bluelock-vcloud-zone01.identity>FIXME_IDENTITY</test.bluelock-vcloud-zone01.identity>
<test.bluelock-vcloud-zone01.credential>FIXME_CREDENTIAL</test.bluelock-vcloud-zone01.credential>
<test.bluelock-vcloud-zone01.image-id />
diff --git a/providers/bluelock-vcloud-zone01/src/main/java/org/jclouds/bluelock/vcloud/zone01/BluelockVCloudZone01PropertiesBuilder.java b/providers/bluelock-vcloud-zone01/src/main/java/org/jclouds/bluelock/vcloud/zone01/BluelockVCloudZone01PropertiesBuilder.java
index a29a175..8d0c803 100644
--- a/providers/bluelock-vcloud-zone01/src/main/java/org/jclouds/bluelock/vcloud/zone01/BluelockVCloudZone01PropertiesBuilder.java
+++ b/providers/bluelock-vcloud-zone01/src/main/java/org/jclouds/bluelock/vcloud/zone01/BluelockVCloudZone01PropertiesBuilder.java
@@ -18,7 +18,7 @@
*/
package org.jclouds.bluelock.vcloud.zone01;
-import static org.jclouds.Constants.PROPERTY_ENDPOINT;
+import static org.jclouds.Constants.*;
import static org.jclouds.Constants.PROPERTY_ISO3166_CODES;
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_NETWORK;
@@ -37,6 +37,7 @@
Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_ISO3166_CODES, "US-IN");
properties.setProperty(PROPERTY_ENDPOINT, "https://zone01.bluelock.com/api");
+ properties.setProperty(PROPERTY_BUILD_VERSION, "1.0.0.285979");
properties.setProperty(PROPERTY_VCLOUD_DEFAULT_NETWORK, "internet01-.*");
return properties;
}
diff --git a/providers/bluelock-vcloud-zone01/src/test/java/org/jclouds/bluelock/vcloud/zone01/compute/BluelockVCloudZone01ComputeServiceLiveTest.java b/providers/bluelock-vcloud-zone01/src/test/java/org/jclouds/bluelock/vcloud/zone01/compute/BluelockVCloudZone01ComputeServiceLiveTest.java
index e0d12c3..fbed5ff 100644
--- a/providers/bluelock-vcloud-zone01/src/test/java/org/jclouds/bluelock/vcloud/zone01/compute/BluelockVCloudZone01ComputeServiceLiveTest.java
+++ b/providers/bluelock-vcloud-zone01/src/test/java/org/jclouds/bluelock/vcloud/zone01/compute/BluelockVCloudZone01ComputeServiceLiveTest.java
@@ -18,8 +18,6 @@
*/
package org.jclouds.bluelock.vcloud.zone01.compute;
-import org.jclouds.compute.domain.ExecResponse;
-import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.vcloud.compute.VCloudComputeServiceLiveTest;
import org.testng.annotations.Test;
@@ -34,14 +32,4 @@
provider = "bluelock-vcloud-zone01";
}
- @Override
- public void setServiceDefaults() {
- group = "director";
- }
-
- protected void checkResponseEqualsHostname(ExecResponse execResponse, NodeMetadata node1) {
- // hostname is not completely predictable based on node metadata
- assert execResponse.getOutput().trim().equals("Ubuntu1004") : execResponse + ": " + node1;
- }
-
}
diff --git a/providers/cloudsigma-zrh/src/test/java/org/jclouds/cloudsigma/compute/CloudSigmaZurichComputeServiceLiveTest.java b/providers/cloudsigma-zrh/src/test/java/org/jclouds/cloudsigma/compute/CloudSigmaZurichComputeServiceLiveTest.java
index 02213e0..fd25db4 100644
--- a/providers/cloudsigma-zrh/src/test/java/org/jclouds/cloudsigma/compute/CloudSigmaZurichComputeServiceLiveTest.java
+++ b/providers/cloudsigma-zrh/src/test/java/org/jclouds/cloudsigma/compute/CloudSigmaZurichComputeServiceLiveTest.java
@@ -18,8 +18,26 @@
*/
package org.jclouds.cloudsigma.compute;
+import org.jclouds.cloudsigma.CloudSigmaClient;
+import org.jclouds.cloudsigma.compute.options.CloudSigmaTemplateOptions;
+import org.jclouds.cloudsigma.domain.AffinityType;
+import org.jclouds.cloudsigma.domain.Device;
+import org.jclouds.cloudsigma.domain.DriveInfo;
+import org.jclouds.cloudsigma.domain.ServerInfo;
+import org.jclouds.compute.RunNodesException;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.domain.TemplateBuilder;
import org.testng.annotations.Test;
+import java.util.Set;
+
+import static com.google.common.collect.Iterables.contains;
+import static com.google.common.collect.Iterables.get;
+import static org.jclouds.cloudsigma.compute.options.CloudSigmaTemplateOptions.Builder.diskDriveAffinity;
+import static org.jclouds.compute.predicates.NodePredicates.inGroup;
+import static org.testng.Assert.assertTrue;
+
/**
*
* @author Adrian Cole
@@ -31,4 +49,34 @@
provider = "cloudsigma-zrh";
}
+ @Test
+ public void testStartNodeWithSSD() throws RunNodesException {
+ String group = this.group + "-ssd";
+
+ TemplateBuilder builder = client.templateBuilder();
+ assert builder instanceof CloudSigmaTemplateBuilderImpl;
+
+ Template template = builder.options(diskDriveAffinity(AffinityType.SSD)).build();
+ assert template.getOptions() instanceof CloudSigmaTemplateOptions;
+
+ try {
+ Set<? extends NodeMetadata> nodes = client.createNodesInGroup(group, 1, template);
+ NodeMetadata node = get(nodes, 0);
+
+ CloudSigmaClient api = CloudSigmaClient.class.cast(client.getContext()
+ .getProviderSpecificContext().getApi());
+
+ // Note: I wanted to use node.getHardware().getVolumes() but there is no
+ // way to go from a Volume to a DriveInfo
+
+ ServerInfo serverInfo = api.getServerInfo(node.getId());
+ Device rootDevice = get(serverInfo.getDevices().values(), 0);
+ DriveInfo driveInfo = api.getDriveInfo(rootDevice.getDriveUuid());
+ assertTrue(contains(driveInfo.getTags(), "affinity:ssd"));
+
+ } finally {
+ client.destroyNodesMatching(inGroup(group));
+ }
+ }
+
}
diff --git a/providers/go2cloud-jhb1/src/test/java/org/jclouds/go2cloud/compute/Go2CloudJohannesburg1TemplateBuilderLiveTest.java b/providers/go2cloud-jhb1/src/test/java/org/jclouds/go2cloud/compute/Go2CloudJohannesburg1TemplateBuilderLiveTest.java
index e2efc78..fc46ea9 100644
--- a/providers/go2cloud-jhb1/src/test/java/org/jclouds/go2cloud/compute/Go2CloudJohannesburg1TemplateBuilderLiveTest.java
+++ b/providers/go2cloud-jhb1/src/test/java/org/jclouds/go2cloud/compute/Go2CloudJohannesburg1TemplateBuilderLiveTest.java
@@ -57,7 +57,7 @@
case DEBIAN:
return (input.version.equals("") || input.version.equals("6.0")) && input.is64Bit;
case WINDOWS:
- return (input.version.equals("") || input.version.equals("2008 R2")) && input.is64Bit;
+ return input.version.equals("") && input.is64Bit;
default:
return false;
}
diff --git a/providers/greenhousedata-element-vcloud/pom.xml b/providers/greenhousedata-element-vcloud/pom.xml
index 7b1ce76..f407917 100644
--- a/providers/greenhousedata-element-vcloud/pom.xml
+++ b/providers/greenhousedata-element-vcloud/pom.xml
@@ -36,10 +36,12 @@
<properties>
<test.greenhousedata-element-vcloud.endpoint>https://mycloud.greenhousedata.com/api</test.greenhousedata-element-vcloud.endpoint>
<test.greenhousedata-element-vcloud.api-version>1.0</test.greenhousedata-element-vcloud.api-version>
- <test.greenhousedata-element-vcloud.build-version />
+ <test.greenhousedata-element-vcloud.build-version>1.5.0.464915</test.greenhousedata-element-vcloud.build-version>
<test.greenhousedata-element-vcloud.identity>FIXME_IDENTITY</test.greenhousedata-element-vcloud.identity>
<test.greenhousedata-element-vcloud.credential>FIXME_CREDENTIAL</test.greenhousedata-element-vcloud.credential>
- <test.greenhousedata-element-vcloud.image-id />
+ <test.greenhousedata-element-vcloud.image-id></test.greenhousedata-element-vcloud.image-id>
+ <test.greenhousedata-element-vcloud.image.login-user></test.greenhousedata-element-vcloud.image.login-user>
+ <test.greenhousedata-element-vcloud.image.authenticate-sudo></test.greenhousedata-element-vcloud.image.authenticate-sudo>
</properties>
<dependencies>
@@ -106,6 +108,8 @@
<test.greenhousedata-element-vcloud.identity>${test.greenhousedata-element-vcloud.identity}</test.greenhousedata-element-vcloud.identity>
<test.greenhousedata-element-vcloud.credential>${test.greenhousedata-element-vcloud.credential}</test.greenhousedata-element-vcloud.credential>
<test.greenhousedata-element-vcloud.image-id>${test.greenhousedata-element-vcloud.image-id}</test.greenhousedata-element-vcloud.image-id>
+ <test.greenhousedata-element-vcloud.image.login-user>${test.greenhousedata-element-vcloud.image.login-user}</test.greenhousedata-element-vcloud.image.login-user>
+ <test.greenhousedata-element-vcloud.image.authenticate-sudo>${test.greenhousedata-element-vcloud.image.authenticate-sudo}</test.greenhousedata-element-vcloud.image.authenticate-sudo>
</systemPropertyVariables>
</configuration>
</execution>
diff --git a/providers/greenhousedata-element-vcloud/src/main/java/org/jclouds/greenhousedata/element/vcloud/GreenHouseDataElementVCloudPropertiesBuilder.java b/providers/greenhousedata-element-vcloud/src/main/java/org/jclouds/greenhousedata/element/vcloud/GreenHouseDataElementVCloudPropertiesBuilder.java
index e4bcc9f..2e83251 100644
--- a/providers/greenhousedata-element-vcloud/src/main/java/org/jclouds/greenhousedata/element/vcloud/GreenHouseDataElementVCloudPropertiesBuilder.java
+++ b/providers/greenhousedata-element-vcloud/src/main/java/org/jclouds/greenhousedata/element/vcloud/GreenHouseDataElementVCloudPropertiesBuilder.java
@@ -18,6 +18,7 @@
*/
package org.jclouds.greenhousedata.element.vcloud;
+import static org.jclouds.Constants.PROPERTY_BUILD_VERSION;
import static org.jclouds.Constants.PROPERTY_ENDPOINT;
import static org.jclouds.Constants.PROPERTY_ISO3166_CODES;
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_NETWORK;
@@ -36,6 +37,7 @@
Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_ISO3166_CODES, "US-WY");
properties.setProperty(PROPERTY_ENDPOINT, "https://mycloud.greenhousedata.com/api");
+ properties.setProperty(PROPERTY_BUILD_VERSION, "1.5.0.464915");
properties.setProperty(PROPERTY_VCLOUD_DEFAULT_NETWORK, "orgNet-.*-External");
return properties;
}
diff --git a/providers/greenhousedata-element-vcloud/src/test/java/org/jclouds/greenhousedata/element/vcloud/compute/GreenHouseDataElementVCloudComputeServiceLiveTest.java b/providers/greenhousedata-element-vcloud/src/test/java/org/jclouds/greenhousedata/element/vcloud/compute/GreenHouseDataElementVCloudComputeServiceLiveTest.java
index 5aab18a..679d1b4 100644
--- a/providers/greenhousedata-element-vcloud/src/test/java/org/jclouds/greenhousedata/element/vcloud/compute/GreenHouseDataElementVCloudComputeServiceLiveTest.java
+++ b/providers/greenhousedata-element-vcloud/src/test/java/org/jclouds/greenhousedata/element/vcloud/compute/GreenHouseDataElementVCloudComputeServiceLiveTest.java
@@ -18,8 +18,6 @@
*/
package org.jclouds.greenhousedata.element.vcloud.compute;
-import org.jclouds.compute.domain.ExecResponse;
-import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.vcloud.compute.VCloudComputeServiceLiveTest;
import org.testng.annotations.Test;
@@ -32,17 +30,6 @@
public class GreenHouseDataElementVCloudComputeServiceLiveTest extends VCloudComputeServiceLiveTest {
public GreenHouseDataElementVCloudComputeServiceLiveTest() {
provider = "greenhousedata-element-vcloud";
- // vcloud requires instantiate before deploy, which takes longer than 30 seconds
- nonBlockDurationSeconds = 300;
}
-
- @Override
- public void setServiceDefaults() {
- group = "director";
- }
-
- protected void checkResponseEqualsHostname(ExecResponse execResponse, NodeMetadata node1) {
- // hostname is not predictable based on node metadata
- assert execResponse.getOutput().trim().equals("(none)");
- }
-}
+
+}
\ No newline at end of file
diff --git a/providers/greenhousedata-element-vcloud/src/test/java/org/jclouds/greenhousedata/element/vcloud/features/GreenHouseDataElementVCloudVmClientLiveTest.java b/providers/greenhousedata-element-vcloud/src/test/java/org/jclouds/greenhousedata/element/vcloud/features/GreenHouseDataElementVCloudVmClientLiveTest.java
index 24eaf28..4527c2e 100644
--- a/providers/greenhousedata-element-vcloud/src/test/java/org/jclouds/greenhousedata/element/vcloud/features/GreenHouseDataElementVCloudVmClientLiveTest.java
+++ b/providers/greenhousedata-element-vcloud/src/test/java/org/jclouds/greenhousedata/element/vcloud/features/GreenHouseDataElementVCloudVmClientLiveTest.java
@@ -18,7 +18,6 @@
*/
package org.jclouds.greenhousedata.element.vcloud.features;
-import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.vcloud.features.VmClientLiveTest;
import org.testng.annotations.Test;
@@ -33,15 +32,5 @@
public GreenHouseDataElementVCloudVmClientLiveTest() {
provider = "greenhousedata-element-vcloud";
}
-
- @Override
- protected void checkApiOutput(String apiOutput) {
- checkApiOutput1_0_0(apiOutput);
- }
- @Override
- protected void checkCustomizationOccurred(ExecResponse exec) {
- // for some reason customization doesn't actually occur
- assert exec.getOutput().equals("") : exec;
- }
}
diff --git a/providers/greenhousedata-element-vcloud/src/test/resources/log4j.xml b/providers/greenhousedata-element-vcloud/src/test/resources/log4j.xml
index 63810d3..daefa0e 100644
--- a/providers/greenhousedata-element-vcloud/src/test/resources/log4j.xml
+++ b/providers/greenhousedata-element-vcloud/src/test/resources/log4j.xml
@@ -120,7 +120,13 @@
<priority value="DEBUG" />
<appender-ref ref="ASYNC" />
</category>
-
+
+ <!-- set to trace to get more info when parser fail -->
+ <category name="org.jclouds.http.functions.ParseSax">
+ <priority value="TRACE" />
+ <appender-ref ref="ASYNC" />
+ </category>
+
<category name="jclouds.headers">
<priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" />
diff --git a/providers/softlayer/src/test/java/org/jclouds/softlayer/features/ProductPackageClientLiveTest.java b/providers/softlayer/src/test/java/org/jclouds/softlayer/features/ProductPackageClientLiveTest.java
index f081155..ad88031 100644
--- a/providers/softlayer/src/test/java/org/jclouds/softlayer/features/ProductPackageClientLiveTest.java
+++ b/providers/softlayer/src/test/java/org/jclouds/softlayer/features/ProductPackageClientLiveTest.java
@@ -22,7 +22,6 @@
import static org.jclouds.softlayer.predicates.ProductItemPredicates.categoryCode;
import static org.jclouds.softlayer.predicates.ProductItemPredicates.units;
import static org.jclouds.softlayer.predicates.ProductPackagePredicates.named;
-import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
@@ -108,7 +107,6 @@
public void testDatacentersForCloudLayer() {
ImmutableSet.Builder<Datacenter> builder = ImmutableSet.builder();
- builder.add(Datacenter.builder().id(3).name("dal01").longName("Dallas").build());
builder.add(Datacenter.builder().id(18171).name("sea01").longName("Seattle").build());
builder.add(Datacenter.builder().id(37473).name("wdc01").longName("Washington, DC").build());
builder.add(Datacenter.builder().id(138124).name("dal05").longName("Dallas 5").build());
@@ -119,7 +117,7 @@
Set<Datacenter> expected = builder.build();
Set<Datacenter> datacenters = cloudServerProductPackage.getDatacenters();
- assertEquals(datacenters.size(), expected.size());
+ assert datacenters.size() == expected.size() : datacenters;
assertTrue(datacenters.containsAll(expected));
for (Datacenter dataCenter : datacenters) {
diff --git a/providers/softlayer/src/test/java/org/jclouds/softlayer/features/VirtualGuestClientExpectTest.java b/providers/softlayer/src/test/java/org/jclouds/softlayer/features/VirtualGuestClientExpectTest.java
index d4c8124..a6eb5eb 100644
--- a/providers/softlayer/src/test/java/org/jclouds/softlayer/features/VirtualGuestClientExpectTest.java
+++ b/providers/softlayer/src/test/java/org/jclouds/softlayer/features/VirtualGuestClientExpectTest.java
@@ -46,8 +46,8 @@
.endpoint(URI.create("https://api.softlayer.com/rest/v3/SoftLayer_Billing_Item/11/cancelService.json"))
.headers(
ImmutableMultimap.<String, String> builder()
- .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
- .put("Accept", "application/json").build()).build();
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()).build();
HttpResponse found = HttpResponse.builder().statusCode(200).build();
diff --git a/providers/stratogen-vcloud-mycloud/pom.xml b/providers/stratogen-vcloud-mycloud/pom.xml
index 8ad7a3de..6e51617 100644
--- a/providers/stratogen-vcloud-mycloud/pom.xml
+++ b/providers/stratogen-vcloud-mycloud/pom.xml
@@ -36,10 +36,12 @@
<properties>
<test.stratogen-vcloud-mycloud.endpoint>https://vcd.stratogen.net/api</test.stratogen-vcloud-mycloud.endpoint>
<test.stratogen-vcloud-mycloud.api-version>1.0</test.stratogen-vcloud-mycloud.api-version>
- <test.stratogen-vcloud-mycloud.build-version />
+ <test.stratogen-vcloud-mycloud.build-version>1.5.0.464915</test.stratogen-vcloud-mycloud.build-version>
<test.stratogen-vcloud-mycloud.identity>FIXME_IDENTITY</test.stratogen-vcloud-mycloud.identity>
<test.stratogen-vcloud-mycloud.credential>FIXME_CREDENTIAL</test.stratogen-vcloud-mycloud.credential>
- <test.stratogen-vcloud-mycloud.image-id />
+ <test.stratogen-vcloud-mycloud.image-id></test.stratogen-vcloud-mycloud.image-id>
+ <test.stratogen-vcloud-mycloud.image.login-user></test.stratogen-vcloud-mycloud.image.login-user>
+ <test.stratogen-vcloud-mycloud.image.authenticate-sudo></test.stratogen-vcloud-mycloud.image.authenticate-sudo>
</properties>
<dependencies>
@@ -106,6 +108,8 @@
<test.stratogen-vcloud-mycloud.identity>${test.stratogen-vcloud-mycloud.identity}</test.stratogen-vcloud-mycloud.identity>
<test.stratogen-vcloud-mycloud.credential>${test.stratogen-vcloud-mycloud.credential}</test.stratogen-vcloud-mycloud.credential>
<test.stratogen-vcloud-mycloud.image-id>${test.stratogen-vcloud-mycloud.image-id}</test.stratogen-vcloud-mycloud.image-id>
+ <test.stratogen-vcloud-mycloud.image.login-user>${test.stratogen-vcloud-mycloud.image.login-user}</test.stratogen-vcloud-mycloud.image.login-user>
+ <test.stratogen-vcloud-mycloud.image.authenticate-sudo>${test.stratogen-vcloud-mycloud.image.authenticate-sudo}</test.stratogen-vcloud-mycloud.image.authenticate-sudo>
</systemPropertyVariables>
</configuration>
</execution>
diff --git a/providers/stratogen-vcloud-mycloud/src/main/java/org/jclouds/stratogen/vcloud/mycloud/StratoGenVCloudMyCloudPropertiesBuilder.java b/providers/stratogen-vcloud-mycloud/src/main/java/org/jclouds/stratogen/vcloud/mycloud/StratoGenVCloudMyCloudPropertiesBuilder.java
index 2ce7fe0..ddcd6be 100644
--- a/providers/stratogen-vcloud-mycloud/src/main/java/org/jclouds/stratogen/vcloud/mycloud/StratoGenVCloudMyCloudPropertiesBuilder.java
+++ b/providers/stratogen-vcloud-mycloud/src/main/java/org/jclouds/stratogen/vcloud/mycloud/StratoGenVCloudMyCloudPropertiesBuilder.java
@@ -18,6 +18,7 @@
*/
package org.jclouds.stratogen.vcloud.mycloud;
+import static org.jclouds.Constants.PROPERTY_BUILD_VERSION;
import static org.jclouds.Constants.PROPERTY_ENDPOINT;
import static org.jclouds.Constants.PROPERTY_ISO3166_CODES;
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_NETWORK;
@@ -37,6 +38,7 @@
Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_ISO3166_CODES, "GB");
properties.setProperty(PROPERTY_ENDPOINT, "https://vcd.stratogen.net/api");
+ properties.setProperty(PROPERTY_BUILD_VERSION, "1.5.0.464915");
properties.setProperty(PROPERTY_VCLOUD_DEFAULT_NETWORK, "Direct Internet");
return properties;
}
diff --git a/providers/stratogen-vcloud-mycloud/src/main/java/org/jclouds/stratogen/vcloud/mycloud/config/StratoGenVCloudMyCloudComputeServiceContextModule.java b/providers/stratogen-vcloud-mycloud/src/main/java/org/jclouds/stratogen/vcloud/mycloud/config/StratoGenVCloudMyCloudComputeServiceContextModule.java
index 56e5134..a10b42f 100644
--- a/providers/stratogen-vcloud-mycloud/src/main/java/org/jclouds/stratogen/vcloud/mycloud/config/StratoGenVCloudMyCloudComputeServiceContextModule.java
+++ b/providers/stratogen-vcloud-mycloud/src/main/java/org/jclouds/stratogen/vcloud/mycloud/config/StratoGenVCloudMyCloudComputeServiceContextModule.java
@@ -18,6 +18,7 @@
*/
package org.jclouds.stratogen.vcloud.mycloud.config;
+import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.vcloud.compute.config.VCloudComputeServiceContextModule;
import org.jclouds.vcloud.compute.options.VCloudTemplateOptions;
@@ -31,6 +32,12 @@
* @author Adrian Cole
*/
public class StratoGenVCloudMyCloudComputeServiceContextModule extends VCloudComputeServiceContextModule {
+
+ @Override
+ protected TemplateBuilder provideTemplate(Injector injector, TemplateBuilder template) {
+ return template.imageNameMatches("Ubuntu server 11.04 64bit no GUI (base)");
+ }
+
@Override
protected TemplateOptions provideTemplateOptions(Injector injector, TemplateOptions options) {
return options.as(VCloudTemplateOptions.class).ipAddressAllocationMode(IpAddressAllocationMode.POOL);
diff --git a/providers/stratogen-vcloud-mycloud/src/test/java/org/jclouds/stratogen/vcloud/mycloud/compute/StratoGenVCloudMyCloudComputeServiceLiveTest.java b/providers/stratogen-vcloud-mycloud/src/test/java/org/jclouds/stratogen/vcloud/mycloud/compute/StratoGenVCloudMyCloudComputeServiceLiveTest.java
index 33222f6..941b72b 100644
--- a/providers/stratogen-vcloud-mycloud/src/test/java/org/jclouds/stratogen/vcloud/mycloud/compute/StratoGenVCloudMyCloudComputeServiceLiveTest.java
+++ b/providers/stratogen-vcloud-mycloud/src/test/java/org/jclouds/stratogen/vcloud/mycloud/compute/StratoGenVCloudMyCloudComputeServiceLiveTest.java
@@ -18,16 +18,8 @@
*/
package org.jclouds.stratogen.vcloud.mycloud.compute;
-import static org.jclouds.compute.util.ComputeServiceUtils.getCores;
-import static org.testng.Assert.assertEquals;
-
import org.jclouds.compute.domain.ExecResponse;
-import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
-import org.jclouds.compute.domain.OsFamily;
-import org.jclouds.compute.domain.Template;
-import org.jclouds.compute.domain.TemplateBuilder;
-import org.jclouds.compute.predicates.OperatingSystemPredicates;
import org.jclouds.vcloud.compute.VCloudComputeServiceLiveTest;
import org.testng.annotations.Test;
@@ -40,34 +32,6 @@
public class StratoGenVCloudMyCloudComputeServiceLiveTest extends VCloudComputeServiceLiveTest {
public StratoGenVCloudMyCloudComputeServiceLiveTest() {
provider = "stratogen-vcloud-mycloud";
- // vcloud requires instantiate before deploy, which takes longer than 30
- // seconds
- nonBlockDurationSeconds = 300;
- }
-
- @Override
- public void setServiceDefaults() {
- group = "director";
- }
-
- @Test
- public void testTemplateBuilder() {
- Template defaultTemplate = client.templateBuilder().build();
- assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true);
- assert OperatingSystemPredicates.supportsApt().apply(defaultTemplate.getImage().getOperatingSystem());
- assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU);
- assertEquals(defaultTemplate.getImage().getOperatingSystem().getDescription(), "Ubuntu Linux (64-bit)");
- assert defaultTemplate.getLocation().getId() != null : defaultTemplate.getLocation();
- assertEquals(getCores(defaultTemplate.getHardware()), 1.0d);
- System.out.println(defaultTemplate.getHardware());
- }
-
- @Override
- protected Template buildTemplate(TemplateBuilder templateBuilder) {
- Template template = super.buildTemplate(templateBuilder);
- Image image = template.getImage();
- assert image.getDefaultCredentials().credential != null : image;
- return template;
}
protected void checkResponseEqualsHostname(ExecResponse execResponse, NodeMetadata node1) {
diff --git a/providers/stratogen-vcloud-mycloud/src/test/java/org/jclouds/stratogen/vcloud/mycloud/compute/StratoGenVCloudMyCloudTemplateBuilderLiveTest.java b/providers/stratogen-vcloud-mycloud/src/test/java/org/jclouds/stratogen/vcloud/mycloud/compute/StratoGenVCloudMyCloudTemplateBuilderLiveTest.java
index 0907523..5d03161 100644
--- a/providers/stratogen-vcloud-mycloud/src/test/java/org/jclouds/stratogen/vcloud/mycloud/compute/StratoGenVCloudMyCloudTemplateBuilderLiveTest.java
+++ b/providers/stratogen-vcloud-mycloud/src/test/java/org/jclouds/stratogen/vcloud/mycloud/compute/StratoGenVCloudMyCloudTemplateBuilderLiveTest.java
@@ -31,6 +31,7 @@
import org.testng.annotations.Test;
import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableSet;
/**
@@ -46,24 +47,31 @@
@Override
protected Predicate<OsFamilyVersion64Bit> defineUnsupportedOperatingSystems() {
- return new Predicate<OsFamilyVersion64Bit>() {
+ return Predicates.not(new Predicate<OsFamilyVersion64Bit>() {
@Override
public boolean apply(OsFamilyVersion64Bit input) {
switch (input.family) {
case UBUNTU:
- return !input.version.equals("") || !input.is64Bit;
+ return input.version.equals("");
+ case DEBIAN:
+ return input.version.equals("") && !input.is64Bit;
+ case RHEL:
+ return input.version.equals("") && input.is64Bit;
+ case WINDOWS:
+ return input.version.equals("") && input.is64Bit;
default:
- return true;
+ return false;
}
}
- };
+ });
}
@Override
public void testDefaultTemplateBuilder() throws IOException {
Template defaultTemplate = context.getComputeService().templateBuilder().build();
+ assertEquals(defaultTemplate.getImage().getName(), "Ubuntu server 11.04 64bit no GUI (base)");
assertEquals(defaultTemplate.getImage().getOperatingSystem().getVersion(), "");
assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true);
assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU);
diff --git a/providers/stratogen-vcloud-mycloud/src/test/resources/log4j.xml b/providers/stratogen-vcloud-mycloud/src/test/resources/log4j.xml
index 63810d3..a301f89 100644
--- a/providers/stratogen-vcloud-mycloud/src/test/resources/log4j.xml
+++ b/providers/stratogen-vcloud-mycloud/src/test/resources/log4j.xml
@@ -120,7 +120,13 @@
<priority value="DEBUG" />
<appender-ref ref="ASYNC" />
</category>
-
+
+ <!-- set to trace to get more info when parser fail -->
+ <category name="org.jclouds.http.functions.ParseSax">
+ <priority value="TRACE" />
+ <appender-ref ref="ASYNC" />
+ </category>
+
<category name="jclouds.headers">
<priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" />
@@ -132,7 +138,7 @@
</category>
<category name="jclouds.wire">
- <priority value="DEBUG" />
+ <priority value="TRACE" />
<appender-ref ref="ASYNCWIRE" />
</category>
diff --git a/providers/trmk-vcloudexpress/src/main/java/org/jclouds/trmk/vcloudexpress/TerremarkVCloudExpressPropertiesBuilder.java b/providers/trmk-vcloudexpress/src/main/java/org/jclouds/trmk/vcloudexpress/TerremarkVCloudExpressPropertiesBuilder.java
index cb2b077..5c798c9 100644
--- a/providers/trmk-vcloudexpress/src/main/java/org/jclouds/trmk/vcloudexpress/TerremarkVCloudExpressPropertiesBuilder.java
+++ b/providers/trmk-vcloudexpress/src/main/java/org/jclouds/trmk/vcloudexpress/TerremarkVCloudExpressPropertiesBuilder.java
@@ -23,7 +23,6 @@
import static org.jclouds.Constants.PROPERTY_ISO3166_CODES;
import static org.jclouds.trmk.vcloud_0_8.reference.TerremarkConstants.PROPERTY_TERREMARK_EXTENSION_NAME;
import static org.jclouds.trmk.vcloud_0_8.reference.TerremarkConstants.PROPERTY_TERREMARK_EXTENSION_VERSION;
-import static org.jclouds.trmk.vcloud_0_8.reference.VCloudConstants.PROPERTY_VCLOUD_TIMEOUT_TASK_COMPLETED;
import java.util.Properties;
@@ -43,7 +42,6 @@
properties.setProperty(PROPERTY_TERREMARK_EXTENSION_NAME, "vCloudExpressExtensions");
properties.setProperty(PROPERTY_TERREMARK_EXTENSION_VERSION, "1.6");
properties.setProperty(PROPERTY_ENDPOINT, "https://services.vcloudexpress.terremark.com/api");
- properties.setProperty(PROPERTY_VCLOUD_TIMEOUT_TASK_COMPLETED, 600l * 1000l + "");
return properties;
}
diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/VirtualBoxPropertiesBuilder.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/VirtualBoxPropertiesBuilder.java
index 7b2014b..2225281 100644
--- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/VirtualBoxPropertiesBuilder.java
+++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/VirtualBoxPropertiesBuilder.java
@@ -64,7 +64,8 @@
properties.put(VIRTUALBOX_ISO_URL, "http://releases.ubuntu.com/11.04/ubuntu-11.04-server-i386.iso");
properties.put(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE, "<Esc><Esc><Enter> "
+ "/install/vmlinuz noapic preseed/url=PRECONFIGURATION_URL "
- + "debian-installer=en_US auto locale=en_US kbd-chooser/method=us " + "hostname=" + "HOSTNAME "
+ + "debian-installer=en_US auto locale=en_US kbd-chooser/method=us "
+ + "hostname=" + "HOSTNAME "
+ "fb=false debconf/frontend=noninteractive "
+ "keyboard-configuration/layout=USA keyboard-configuration/variant=USA console-setup/ask_detect=false "
+ "initrd=/install/initrd.gz -- <Enter>");
diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/IMachineSpec.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/IMachineSpec.java
new file mode 100644
index 0000000..b753d49
--- /dev/null
+++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/IMachineSpec.java
@@ -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.virtualbox.domain;
+
+import com.google.common.base.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * A complete specification of a "master" node, including the ISO, networking setup
+ * and the physical machine specification.
+ */
+public class IMachineSpec {
+
+ private VmSpec vmSpec;
+ private IsoSpec isoSpec;
+ private NetworkSpec networkSpec;
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+
+ private VmSpec vmSpec;
+ private IsoSpec isoSpec;
+ private NetworkSpec networkSpec;
+
+ public Builder vm(VmSpec vmSpec) {
+ this.vmSpec = vmSpec;
+ return this;
+ }
+
+ public Builder network(NetworkSpec networkSpec) {
+ this.networkSpec = networkSpec;
+ return this;
+ }
+
+ public Builder iso(IsoSpec isoSpec) {
+ this.isoSpec = isoSpec;
+ return this;
+ }
+
+ public IMachineSpec build() {
+ return new IMachineSpec(vmSpec, isoSpec, networkSpec);
+ }
+
+ }
+
+ public IMachineSpec(VmSpec vmSpec, IsoSpec isoSpec, NetworkSpec networkSpec) {
+ checkNotNull(vmSpec, "vmSpec");
+ checkNotNull(isoSpec, "isoSpec");
+ checkNotNull(networkSpec, "networkSpec");
+ this.vmSpec = vmSpec;
+ this.isoSpec = isoSpec;
+ this.networkSpec = networkSpec;
+ }
+
+ public VmSpec getVmSpec() {
+ return vmSpec;
+ }
+
+ public IsoSpec getIsoSpec() {
+ return isoSpec;
+ }
+
+ public NetworkSpec getNetworkSpec() {
+ return networkSpec;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o instanceof VmSpec) {
+ IMachineSpec other = (IMachineSpec) o;
+ return Objects.equal(vmSpec, other.vmSpec) &&
+ Objects.equal(isoSpec, other.isoSpec) &&
+ Objects.equal(networkSpec, other.networkSpec);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(vmSpec,isoSpec,networkSpec);
+ }
+
+ @Override
+ public String toString() {
+ return "IMachineSpec{" +
+ "vmSpec=" + vmSpec +
+ ", isoSpec=" + isoSpec +
+ ", networkSpec=" + networkSpec +
+ '}';
+ }
+}
diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/IsoSpec.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/IsoSpec.java
new file mode 100644
index 0000000..2b0bc46
--- /dev/null
+++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/IsoSpec.java
@@ -0,0 +1,116 @@
+/*
+ * 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.virtualbox.domain;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Supplier;
+import org.jclouds.virtualbox.Preconfiguration;
+
+import java.net.URI;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * The information needed to create a machine from a .iso file.
+ */
+public class IsoSpec {
+
+ private final String installationKeySequence;
+ private final String sourcePath;
+ private final Supplier<URI> preConfigurationUri;
+
+ public IsoSpec(String sourcePath, String installationKeySequence, @Preconfiguration Supplier<URI> preConfigurationUri) {
+ checkNotNull(sourcePath, "sourcePath");
+ checkNotNull(installationKeySequence, "installationKeySequence");
+ checkNotNull(preConfigurationUri, "preConfigurationUri");
+ this.sourcePath = sourcePath;
+ this.installationKeySequence = installationKeySequence;
+ this.preConfigurationUri = preConfigurationUri;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+
+ private String installationSequence;
+ private Supplier<URI> preConfigurationUri;
+ private String sourcePath;
+
+ public Builder installationScript(String installationSequence) {
+ this.installationSequence = installationSequence;
+ return this;
+ }
+
+ public Builder preConfiguration(Supplier<URI> preConfigurationUri) {
+ this.preConfigurationUri = preConfigurationUri;
+ return this;
+ }
+
+ public Builder sourcePath(String sourcePath) {
+ this.sourcePath = sourcePath;
+ return this;
+ }
+
+
+ public IsoSpec build() {
+ return new IsoSpec(sourcePath, installationSequence, preConfigurationUri);
+ }
+ }
+
+ public String getInstallationKeySequence() {
+ return installationKeySequence;
+ }
+
+ public Supplier<URI> getPreConfigurationUri() {
+ return preConfigurationUri;
+ }
+
+ public String getSourcePath() {
+ return sourcePath;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o instanceof VmSpec) {
+ IsoSpec other = (IsoSpec) o;
+ return Objects.equal(sourcePath, other.sourcePath) &&
+ Objects.equal(installationKeySequence, other.installationKeySequence) &&
+ Objects.equal(preConfigurationUri, other.preConfigurationUri);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(sourcePath, installationKeySequence, preConfigurationUri);
+ }
+
+ @Override
+ public String toString() {
+ return "IsoSpec{" +
+ "sourcePath='" + sourcePath + '\'' +
+ "installationKeySequence='" + installationKeySequence + '\'' +
+ ", preConfigurationUri=" + preConfigurationUri +
+ '}';
+ }
+}
diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/NetworkSpec.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/NetworkSpec.java
new file mode 100644
index 0000000..72bb8e5
--- /dev/null
+++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/NetworkSpec.java
@@ -0,0 +1,87 @@
+/*
+ * 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.virtualbox.domain;
+
+import com.google.common.base.Objects;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Describes the network configuration for a VirtualBox machine.
+ */
+public class NetworkSpec {
+
+ private final Map<Long, NatAdapter> natNetworkAdapters;
+
+ public NetworkSpec(final Map<Long, NatAdapter> natNetworkAdapters) {
+ checkNotNull(natNetworkAdapters, "natNetworkAdapters");
+ this.natNetworkAdapters = natNetworkAdapters;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+
+ private Map<Long, NatAdapter> natNetworkAdapters = new HashMap<Long, NatAdapter>();
+
+ public Builder natNetworkAdapter(int slot, NatAdapter adapter) {
+ this.natNetworkAdapters.put((long) slot, adapter);
+ return this;
+ }
+
+ public NetworkSpec build() {
+ return new NetworkSpec(natNetworkAdapters);
+ }
+ }
+
+
+ public Map<Long, NatAdapter> getNatNetworkAdapters() {
+ return Collections.unmodifiableMap(natNetworkAdapters);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o instanceof VmSpec) {
+ NetworkSpec other = (NetworkSpec) o;
+ return Objects.equal(natNetworkAdapters, other.natNetworkAdapters);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(natNetworkAdapters);
+ }
+
+
+ @Override
+ public String toString() {
+ return "NetworkSpec{" +
+ "natNetworkAdapters=" + natNetworkAdapters +
+ '}';
+ }
+}
diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/VmSpec.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/VmSpec.java
index 8f61cdc..2b9a0c6 100644
--- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/VmSpec.java
+++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/VmSpec.java
@@ -18,18 +18,13 @@
*/
package org.jclouds.virtualbox.domain;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
+import com.google.common.base.Objects;
import org.virtualbox_4_1.CleanupMode;
-import com.google.common.base.Objects;
+import java.util.*;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
/**
* A description of a Virtual Machine in VirtualBox.
@@ -41,16 +36,14 @@
private final String vmId;
private final long memory;
private final boolean forceOverwrite;
- private final Map<Long, NatAdapter> natNetworkAdapters;
private final Set<StorageController> controllers;
private final CleanupMode cleanupMode;
- public VmSpec(String vmId, String vmName, String osTypeId, long memory, boolean forceOverwrite, Set<StorageController> controllers, Map<Long, NatAdapter> natNetworkAdapters, CleanupMode cleanupMode) {
+ public VmSpec(String vmId, String vmName, String osTypeId, long memory, boolean forceOverwrite, Set<StorageController> controllers, CleanupMode cleanupMode) {
checkNotNull(vmId, "vmId");
checkNotNull(vmName, "vmName");
checkArgument(memory > 0, "memory must be > 0");
checkNotNull(controllers, "controllers");
- checkNotNull(natNetworkAdapters, "natNetworkAdapters");
checkNotNull(cleanupMode, "cleanupMode");
this.vmId = vmId;
this.vmName = vmName;
@@ -58,7 +51,6 @@
this.memory = memory;
this.controllers = controllers;
this.forceOverwrite = forceOverwrite;
- this.natNetworkAdapters = natNetworkAdapters;
this.cleanupMode = cleanupMode;
}
@@ -74,10 +66,9 @@
private String id;
private String osTypeId = "";
private boolean forceOverwrite;
- private Map<Long, NatAdapter> natNetworkAdapters = new HashMap<Long, NatAdapter>();
private long memory;
private CleanupMode cleanUpMode;
-
+
public Builder controller(StorageController controller) {
controllers.add(controller);
return this;
@@ -103,30 +94,24 @@
return this;
}
- public Builder natNetworkAdapter(int slot, NatAdapter adapter) {
- this.natNetworkAdapters.put((long) slot, adapter);
- return this;
- }
-
public Builder memoryMB(int memorySize) {
this.memory = (long) memorySize;
return this;
}
-
+
public Builder cleanUpMode(CleanupMode cleanupMode) {
this.cleanUpMode = cleanupMode;
return this;
- }
+ }
public VmSpec build() {
checkNotNull(name, "name");
checkNotNull(id, "id");
checkArgument(memory > 0, "Memory must be set");
- return new VmSpec(id, name, osTypeId, memory, forceOverwrite, controllers, natNetworkAdapters, cleanUpMode);
+ return new VmSpec(id, name, osTypeId, memory, forceOverwrite, controllers, cleanUpMode);
}
-
-
}
+
public String getVmId() {
return vmId;
}
@@ -151,10 +136,6 @@
return Collections.unmodifiableSet(controllers);
}
- public Map<Long, NatAdapter> getNatNetworkAdapters() {
- return Collections.unmodifiableMap(natNetworkAdapters);
- }
-
public CleanupMode getCleanupMode() {
return cleanupMode;
}
@@ -169,7 +150,6 @@
Objects.equal(osTypeId, other.osTypeId) &&
Objects.equal(memory, other.memory) &&
Objects.equal(forceOverwrite, other.forceOverwrite) &&
- Objects.equal(natNetworkAdapters, other.natNetworkAdapters) &&
Objects.equal(controllers, other.controllers) &&
Objects.equal(cleanupMode, other.cleanupMode);
}
@@ -178,7 +158,7 @@
@Override
public int hashCode() {
- return Objects.hashCode(vmId, vmName, osTypeId, memory, forceOverwrite, natNetworkAdapters, controllers);
+ return Objects.hashCode(vmId, vmName, osTypeId, memory, forceOverwrite, controllers);
}
@Override
@@ -189,7 +169,6 @@
", memory='" + memory + '\'' +
", vmId='" + vmId + '\'' +
", forceOverwrite=" + forceOverwrite +
- ", natNetworkAdapters=" + natNetworkAdapters +
", controllers=" + controllers +
", cleanupMode=" + cleanupMode +
'}';
diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/AttachNATAdapterToMachineIfNotAlreadyExists.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/AttachNATAdapterToMachineIfNotAlreadyExists.java
index 8aced46..10d8f0b 100644
--- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/AttachNATAdapterToMachineIfNotAlreadyExists.java
+++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/AttachNATAdapterToMachineIfNotAlreadyExists.java
@@ -55,7 +55,7 @@
networkAdapter.getNatDriver().addRedirect(ruleName, rule.getProtocol(), rule.getHost(), rule.getHostPort(),
rule.getGuest(), rule.getGuestPort());
} catch (VBoxException e) {
- if (e.getMessage().indexOf("already exists") == -1)
+ if (!e.getMessage().contains("already exists"))
throw e;
}
}
diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndInstallVm.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndInstallVm.java
index 9d86fd6..e128bfb 100644
--- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndInstallVm.java
+++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndInstallVm.java
@@ -18,30 +18,20 @@
*/
package org.jclouds.virtualbox.functions;
-import static com.google.common.base.Preconditions.checkState;
-import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot;
-import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE;
-import static org.jclouds.virtualbox.util.MachineUtils.applyForMachine;
-import static org.jclouds.virtualbox.util.MachineUtils.lockSessionOnMachineAndApply;
-import static org.virtualbox_4_1.LockType.Shared;
-
-import java.net.URI;
-import java.util.List;
-
-import javax.annotation.Resource;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.inject.Inject;
import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.callables.RunScriptOnNode.Factory;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.reference.ComputeServiceConstants;
-import org.jclouds.config.ValueOfConfigurationKeyOrNull;
import org.jclouds.logging.Logger;
import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.ssh.SshClient;
-import org.jclouds.virtualbox.Preconfiguration;
import org.jclouds.virtualbox.domain.ExecutionType;
+import org.jclouds.virtualbox.domain.IMachineSpec;
+import org.jclouds.virtualbox.domain.IsoSpec;
import org.jclouds.virtualbox.domain.VmSpec;
import org.jclouds.virtualbox.settings.KeyboardScancodes;
import org.virtualbox_4_1.IMachine;
@@ -49,16 +39,19 @@
import org.virtualbox_4_1.ISession;
import org.virtualbox_4_1.VirtualBoxManager;
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.base.Splitter;
-import com.google.common.base.Supplier;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.inject.Inject;
+import javax.annotation.Resource;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import java.net.URI;
+
+import static com.google.common.base.Preconditions.checkState;
+import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot;
+import static org.jclouds.virtualbox.util.MachineUtils.applyForMachine;
+import static org.jclouds.virtualbox.util.MachineUtils.lockSessionOnMachineAndApply;
+import static org.virtualbox_4_1.LockType.Shared;
@Singleton
-public class CreateAndInstallVm implements Function<VmSpec, IMachine> {
+public class CreateAndInstallVm implements Function<IMachineSpec, IMachine> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
@@ -66,9 +59,7 @@
private final Supplier<VirtualBoxManager> manager;
private final CreateAndRegisterMachineFromIsoIfNotAlreadyExists createAndRegisterMachineFromIsoIfNotAlreadyExists;
- private final ValueOfConfigurationKeyOrNull valueOfConfigurationKeyOrNull;
- private final Supplier<URI> preconfiguration;
private final Predicate<SshClient> sshResponds;
private final ExecutionType executionType;
@@ -78,66 +69,53 @@
private final Function<IMachine, SshClient> sshClientForIMachine;
@Inject
- public CreateAndInstallVm(
- Supplier<VirtualBoxManager> manager,
- CreateAndRegisterMachineFromIsoIfNotAlreadyExists CreateAndRegisterMachineFromIsoIfNotAlreadyExists,
- ValueOfConfigurationKeyOrNull valueOfConfigurationKeyOrNull,
- Predicate<SshClient> sshResponds,
- Function<IMachine, SshClient> sshClientForIMachine,
- Supplier<NodeMetadata> host, RunScriptOnNode.Factory scriptRunner,
- @Preconfiguration Supplier<URI> preconfiguration,
- ExecutionType executionType) {
+ public CreateAndInstallVm(Supplier<VirtualBoxManager> manager,
+ CreateAndRegisterMachineFromIsoIfNotAlreadyExists CreateAndRegisterMachineFromIsoIfNotAlreadyExists,
+ Predicate<SshClient> sshResponds, Function<IMachine, SshClient> sshClientForIMachine,
+ Supplier<NodeMetadata> host, RunScriptOnNode.Factory scriptRunner, ExecutionType executionType) {
this.manager = manager;
this.createAndRegisterMachineFromIsoIfNotAlreadyExists = CreateAndRegisterMachineFromIsoIfNotAlreadyExists;
- this.valueOfConfigurationKeyOrNull = valueOfConfigurationKeyOrNull;
this.sshResponds = sshResponds;
this.sshClientForIMachine = sshClientForIMachine;
this.scriptRunner = scriptRunner;
this.host = host;
- this.preconfiguration = preconfiguration;
this.executionType = executionType;
}
@Override
- public IMachine apply(VmSpec vmSpec) {
+ public IMachine apply(IMachineSpec machineSpec) {
+
+ VmSpec vmSpec = machineSpec.getVmSpec();
+ IsoSpec isoSpec = machineSpec.getIsoSpec();
+
String vmName = vmSpec.getVmName();
- // note this may not be reachable, as this likely uses the 10.2.2 address
- URI preconfigurationUri = preconfiguration.get();
- String keySequence = valueOfConfigurationKeyOrNull
- .apply(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE)
- .replace("PRECONFIGURATION_URL",
- preconfigurationUri.toASCIIString())
- .replace("HOSTNAME", vmName);
-
- final IMachine vm = createAndRegisterMachineFromIsoIfNotAlreadyExists
- .apply(vmSpec);
+ final IMachine vm = createAndRegisterMachineFromIsoIfNotAlreadyExists.apply(machineSpec);
// Launch machine and wait for it to come online
ensureMachineIsLaunched(vmName);
- sendKeyboardSequence(keySequence, vmName);
+ URI uri = isoSpec.getPreConfigurationUri().get();
+ String installationKeySequence = isoSpec.getInstallationKeySequence()
+ .replace("PRECONFIGURATION_URL", uri.toASCIIString());
+ sendKeyboardSequence(installationKeySequence, vmName);
SshClient client = sshClientForIMachine.apply(vm);
logger.debug(">> awaiting installation to finish node(%s)", vmName);
- checkState(sshResponds.apply(client),
- "timed out waiting for guest %s to be accessible via ssh", vmName);
+ checkState(sshResponds.apply(client), "timed out waiting for guest %s to be accessible via ssh", vmName);
- logger.debug("<< installation of image complete. Powering down node(%s)",
- vmName);
- lockSessionOnMachineAndApply(manager.get(), Shared, vmName,
- new Function<ISession, Void>() {
+ logger.debug("<< installation of image complete. Powering down node(%s)", vmName);
+ lockSessionOnMachineAndApply(manager.get(), Shared, vmName, new Function<ISession, Void>() {
- @Override
- public Void apply(ISession session) {
- IProgress powerDownProgress = session.getConsole()
- .powerDown();
- powerDownProgress.waitForCompletion(-1);
- return null;
- }
+ @Override
+ public Void apply(ISession session) {
+ IProgress powerDownProgress = session.getConsole().powerDown();
+ powerDownProgress.waitForCompletion(-1);
+ return null;
+ }
- });
+ });
return vm;
}
diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExists.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExists.java
index 5947b6e..392911c 100644
--- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExists.java
+++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExists.java
@@ -36,12 +36,7 @@
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger;
import org.jclouds.virtualbox.config.VirtualBoxConstants;
-import org.jclouds.virtualbox.domain.DeviceDetails;
-import org.jclouds.virtualbox.domain.HardDisk;
-import org.jclouds.virtualbox.domain.IsoImage;
-import org.jclouds.virtualbox.domain.NatAdapter;
-import org.jclouds.virtualbox.domain.StorageController;
-import org.jclouds.virtualbox.domain.VmSpec;
+import org.jclouds.virtualbox.domain.*;
import org.virtualbox_4_1.AccessMode;
import org.virtualbox_4_1.DeviceType;
import org.virtualbox_4_1.IMachine;
@@ -57,7 +52,7 @@
* @author Mattias Holmqvist
*/
@Singleton
-public class CreateAndRegisterMachineFromIsoIfNotAlreadyExists implements Function<VmSpec, IMachine> {
+public class CreateAndRegisterMachineFromIsoIfNotAlreadyExists implements Function<IMachineSpec, IMachine> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
@@ -74,9 +69,9 @@
}
@Override
- public IMachine apply(@Nullable VmSpec launchSpecification) {
+ public IMachine apply(@Nullable IMachineSpec launchSpecification) {
final IVirtualBox vBox = manager.get().getVBox();
- String vmName = launchSpecification.getVmName();
+ String vmName = launchSpecification.getVmSpec().getVmName();
try {
vBox.findMachine(vmName);
throw new IllegalStateException("Machine " + vmName + " is already registered.");
@@ -92,17 +87,20 @@
return e.getMessage().contains("VirtualBox error: Could not find a registered machine named ");
}
- private IMachine createMachine(IVirtualBox vBox, VmSpec vmSpec) {
+ private IMachine createMachine(IVirtualBox vBox, IMachineSpec machineSpec) {
+ VmSpec vmSpec = machineSpec.getVmSpec();
String settingsFile = vBox.composeMachineFilename(vmSpec.getVmName(), workingDir);
IMachine newMachine = vBox.createMachine(settingsFile, vmSpec.getVmName(), vmSpec.getOsTypeId(),
vmSpec.getVmId(), vmSpec.isForceOverwrite());
manager.get().getVBox().registerMachine(newMachine);
- ensureConfiguration(vmSpec);
+ ensureConfiguration(machineSpec);
return newMachine;
}
- private void ensureConfiguration(VmSpec vmSpec) {
+ private void ensureConfiguration(IMachineSpec machineSpec) {
+ VmSpec vmSpec = machineSpec.getVmSpec();
+ NetworkSpec networkSpec = machineSpec.getNetworkSpec();
String vmName = vmSpec.getVmName();
// Change RAM
@@ -118,7 +116,7 @@
setupDvdsForController(vmSpec, vmName, controller);
// NAT
- Map<Long, NatAdapter> natNetworkAdapters = vmSpec.getNatNetworkAdapters();
+ Map<Long, NatAdapter> natNetworkAdapters = networkSpec.getNatNetworkAdapters();
for (Map.Entry<Long, NatAdapter> natAdapterAndSlot : natNetworkAdapters.entrySet()) {
long slotId = natAdapterAndSlot.getKey();
NatAdapter natAdapter = natAdapterAndSlot.getValue();
diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/RetrieveActiveBridgedInterfaces.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/RetrieveActiveBridgedInterfaces.java
index caa6d97..9fcc0a2 100644
--- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/RetrieveActiveBridgedInterfaces.java
+++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/RetrieveActiveBridgedInterfaces.java
@@ -83,7 +83,8 @@
}
} catch (SocketException e) {
logger.error(e, "Problem in listing network interfaces.");
- propagate(e);
+ Throwables.propagate(e);
+ assert false;
}
return activeNetworkInterfaceNames;
}
@@ -109,12 +110,6 @@
return bridgedInterfaceNames;
}
- protected <T> T propagate(Exception e) {
- Throwables.propagate(e);
- assert false;
- return null;
- }
-
private class IsActiveBridgedInterface implements Predicate<String> {
private NetworkInterface networkInterface;
@@ -130,7 +125,8 @@
.isLoopback());
} catch (SocketException e) {
logger.error(e, "Problem in listing network interfaces.");
- propagate(e);
+ Throwables.propagate(e);
+ assert false;
}
return false;
}
diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/TakeSnapshotIfNotAlreadyAttached.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/TakeSnapshotIfNotAlreadyAttached.java
index 0e80ec0..0331196 100644
--- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/TakeSnapshotIfNotAlreadyAttached.java
+++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/TakeSnapshotIfNotAlreadyAttached.java
@@ -68,18 +68,13 @@
logger.debug("Snapshot %s (description: %s) taken from %s", snapshotName, snapshotDesc, machine.getName());
} catch (Exception e) {
logger.error(e, "Problem creating snapshot %s (descripton: %s) from machine %s", snapshotName, snapshotDesc, machine.getName());
- propogate(e);
+ Throwables.propagate(e);
+ assert false;
} finally {
session.unlockMachine();
}
}
return machine.getCurrentSnapshot();
}
-
- protected <T> T propogate(Exception e) {
- Throwables.propagate(e);
- assert false;
- return null;
- }
}
diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/GetIPAddressFromMAC.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/GetIPAddressFromMAC.java
similarity index 98%
rename from sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/GetIPAddressFromMAC.java
rename to sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/GetIPAddressFromMAC.java
index 19e5bb7..5bea180 100644
--- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/GetIPAddressFromMAC.java
+++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/GetIPAddressFromMAC.java
@@ -16,7 +16,8 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.jclouds.virtualbox.domain;
+
+package org.jclouds.virtualbox.statements;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/InstallGuestAdditions.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/InstallGuestAdditions.java
similarity index 98%
rename from sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/InstallGuestAdditions.java
rename to sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/InstallGuestAdditions.java
index 68ccedc..b0eb11a 100644
--- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/InstallGuestAdditions.java
+++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/InstallGuestAdditions.java
@@ -16,7 +16,8 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.jclouds.virtualbox.domain;
+
+package org.jclouds.virtualbox.statements;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.scriptbuilder.domain.Statements.call;
diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/ScanNetworkWithPing.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/ScanNetworkWithPing.java
similarity index 97%
rename from sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/ScanNetworkWithPing.java
rename to sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/ScanNetworkWithPing.java
index ad9f6de..1a35434 100644
--- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/ScanNetworkWithPing.java
+++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/ScanNetworkWithPing.java
@@ -1,4 +1,4 @@
-/**
+/*
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
@@ -17,7 +17,7 @@
* under the License.
*/
-package org.jclouds.virtualbox.domain;
+package org.jclouds.virtualbox.statements;
import static com.google.common.base.Preconditions.checkNotNull;
diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/Statements.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/Statements.java
similarity index 96%
rename from sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/Statements.java
rename to sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/Statements.java
index 944975a..23ea1dc 100644
--- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/Statements.java
+++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/Statements.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.jclouds.virtualbox.domain;
+package org.jclouds.virtualbox.statements;
import org.jclouds.scriptbuilder.domain.AppendFile;
import org.jclouds.scriptbuilder.domain.Call;
diff --git a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/ExportIpAddressForVMNamedTest.java b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/ExportIpAddressForVMNamedTest.java
index 47a9115..33843e9 100644
--- a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/ExportIpAddressForVMNamedTest.java
+++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/ExportIpAddressForVMNamedTest.java
@@ -19,7 +19,7 @@
package org.jclouds.virtualbox.domain;
import static org.jclouds.scriptbuilder.domain.Statements.interpret;
-import static org.jclouds.virtualbox.domain.Statements.exportIpAddressFromVmNamed;
+import static org.jclouds.virtualbox.statements.Statements.exportIpAddressFromVmNamed;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
diff --git a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/InstallGuestAdditionsTest.java b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/InstallGuestAdditionsTest.java
index 675e2db..8aace24 100644
--- a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/InstallGuestAdditionsTest.java
+++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/InstallGuestAdditionsTest.java
@@ -24,6 +24,7 @@
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.ShellToken;
+import org.jclouds.virtualbox.statements.InstallGuestAdditions;
import org.testng.annotations.Test;
import com.google.common.base.Charsets;
diff --git a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/ScanNetworkWithPingTest.java b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/ScanNetworkWithPingTest.java
index f3801b0..02a352f 100644
--- a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/ScanNetworkWithPingTest.java
+++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/ScanNetworkWithPingTest.java
@@ -21,6 +21,7 @@
import static org.testng.Assert.assertEquals;
import org.jclouds.scriptbuilder.domain.OsFamily;
+import org.jclouds.virtualbox.statements.ScanNetworkWithPing;
import org.testng.annotations.Test;
/**
diff --git a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/VmSpecTest.java b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/VmSpecTest.java
index 3b1596f..8d9ec5d 100644
--- a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/VmSpecTest.java
+++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/VmSpecTest.java
@@ -70,9 +70,6 @@
.osTypeId("Ubuntu")
.memoryMB(1024)
.cleanUpMode(CleanupMode.Full)
- .natNetworkAdapter(
- 0,
- NatAdapter.builder().tcpRedirectRule("localhost", 2222, "", 22).build())
.forceOverwrite(true)
.controller(
StorageController.builder().name("Controller")
diff --git a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java
index d4558d1..e71553a 100644
--- a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java
+++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java
@@ -22,10 +22,9 @@
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX;
import static org.testng.Assert.assertEquals;
+import com.google.inject.Injector;
import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest;
-import org.jclouds.virtualbox.domain.HardDisk;
-import org.jclouds.virtualbox.domain.StorageController;
-import org.jclouds.virtualbox.domain.VmSpec;
+import org.jclouds.virtualbox.domain.*;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.virtualbox_4_1.CleanupMode;
@@ -45,7 +44,8 @@
private static final boolean IS_LINKED_CLONE = true;
private VmSpec clonedVmSpec;
- private VmSpec sourceVmSpec;
+ private IMachineSpec sourceMachineSpec;
+
private CleanupMode mode = CleanupMode.Full;
@@ -53,22 +53,25 @@
@BeforeClass(groups = "live")
public void setupClient() {
super.setupClient();
- String sourceName = VIRTUALBOX_IMAGE_PREFIX
- + CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, getClass().getSimpleName());
- String cloneName = VIRTUALBOX_IMAGE_PREFIX
- + "Clone#" + CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, getClass().getSimpleName()
- );
+ String sourceName = VIRTUALBOX_IMAGE_PREFIX
+ + CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, getClass().getSimpleName());
+ String cloneName = VIRTUALBOX_IMAGE_PREFIX
+ + "Clone#" + CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, getClass().getSimpleName()
+ );
StorageController ideController = StorageController.builder().name("IDE Controller").bus(StorageBus.IDE)
- .attachISO(0, 0, operatingSystemIso).attachHardDisk(
- HardDisk.builder().diskpath(adminDisk).controllerPort(0).deviceSlot(1).autoDelete(true).build()).attachISO(1, 1,
- guestAdditionsIso).build();
+ .attachISO(0, 0, operatingSystemIso).attachHardDisk(
+ HardDisk.builder().diskpath(adminDisk).controllerPort(0).deviceSlot(1).autoDelete(true).build()).attachISO(1, 1,
+ guestAdditionsIso).build();
- sourceVmSpec = VmSpec.builder().id(sourceName).name(sourceName).osTypeId("").memoryMB(512).cleanUpMode(
- CleanupMode.Full).controller(ideController).forceOverwrite(true).build();
+ VmSpec sourceVmSpec = VmSpec.builder().id(sourceName).name(sourceName).osTypeId("").memoryMB(512).cleanUpMode(
+ CleanupMode.Full).controller(ideController).forceOverwrite(true).build();
+ IsoSpec isoSpec = IsoSpec.builder().build();
+ NetworkSpec networkSpec = NetworkSpec.builder().build();
+ sourceMachineSpec = IMachineSpec.builder().iso(isoSpec).vm(sourceVmSpec).network(networkSpec).build();
clonedVmSpec = VmSpec.builder().id(cloneName).name(cloneName).memoryMB(512).cleanUpMode(mode)
- .forceOverwrite(true).build();
+ .forceOverwrite(true).build();
}
@Test
@@ -83,10 +86,10 @@
}
IMachine clone = new CloneAndRegisterMachineFromIMachineIfNotAlreadyExists(manager, workingDir, clonedVmSpec,
- IS_LINKED_CLONE).apply(source);
+ IS_LINKED_CLONE).apply(source);
assertEquals(clone.getName(), clonedVmSpec.getVmName());
} finally {
- for (VmSpec spec : ImmutableSet.of(clonedVmSpec, sourceVmSpec))
+ for (VmSpec spec : ImmutableSet.of(clonedVmSpec, sourceMachineSpec.getVmSpec()))
undoVm(spec);
}
@@ -94,11 +97,12 @@
private IMachine getSourceNode() {
try {
- return context.utils().injector().getInstance(CreateAndRegisterMachineFromIsoIfNotAlreadyExists.class).apply(
- sourceVmSpec);
+ Injector injector = context.utils().injector();
+ return injector.getInstance(CreateAndRegisterMachineFromIsoIfNotAlreadyExists.class).apply(
+ sourceMachineSpec);
} catch (IllegalStateException e) {
// already created
- return manager.get().getVBox().findMachine(sourceVmSpec.getVmId());
+ return manager.get().getVBox().findMachine(sourceMachineSpec.getVmSpec().getVmId());
}
}
}
\ No newline at end of file
diff --git a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java
index b3249d1..911bab1 100644
--- a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java
+++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java
@@ -19,28 +19,19 @@
package org.jclouds.virtualbox.functions;
-import static com.google.common.base.Predicates.equalTo;
-import static com.google.common.collect.Iterables.any;
-import static com.google.common.collect.Iterables.transform;
-import static org.testng.Assert.assertTrue;
-import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX;
-
-import java.util.Map;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-
+import com.google.common.base.CaseFormat;
+import com.google.common.base.Function;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
import org.jclouds.compute.config.BaseComputeServiceContextModule;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.config.ValueOfConfigurationKeyOrNull;
import org.jclouds.json.Json;
import org.jclouds.json.config.GsonModule;
import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest;
-import org.jclouds.virtualbox.domain.HardDisk;
-import org.jclouds.virtualbox.domain.NatAdapter;
-import org.jclouds.virtualbox.domain.StorageController;
-import org.jclouds.virtualbox.domain.VmSpec;
+import org.jclouds.virtualbox.domain.*;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@@ -48,9 +39,16 @@
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.StorageBus;
-import com.google.common.base.CaseFormat;
-import com.google.common.base.Function;
-import com.google.inject.Guice;
+import javax.annotation.Nullable;
+import java.util.Map;
+import java.util.Set;
+
+import static com.google.common.base.Predicates.equalTo;
+import static com.google.common.collect.Iterables.any;
+import static com.google.common.collect.Iterables.transform;
+import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX;
+import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE;
+import static org.testng.Assert.assertTrue;
/**
* @author Andrea Turli, Mattias Holmqvist
@@ -68,11 +66,11 @@
@BeforeClass(groups = "live")
public void setupClient() {
super.setupClient();
- String vmName = VIRTUALBOX_IMAGE_PREFIX
- + CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, getClass().getSimpleName());
+ String vmName = VIRTUALBOX_IMAGE_PREFIX
+ + CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, getClass().getSimpleName());
HardDisk hardDisk = HardDisk.builder().diskpath(adminDisk).autoDelete(true)
- .controllerPort(0).deviceSlot(1).build();
+ .controllerPort(0).deviceSlot(1).build();
StorageController ideController = StorageController.builder().name("IDE Controller").bus(StorageBus.IDE)
.attachISO(0, 0, operatingSystemIso)
.attachHardDisk(hardDisk)
@@ -80,14 +78,26 @@
vmSpecification = VmSpec.builder().id("jclouds-image-iso-1").name(vmName).memoryMB(512).osTypeId("")
.controller(ideController)
.forceOverwrite(true)
- .cleanUpMode(CleanupMode.Full)
- .natNetworkAdapter(0, NatAdapter.builder().tcpRedirectRule("127.0.0.1", 2222, "", 22).build()).build();
+ .cleanUpMode(CleanupMode.Full).build();
undoVm(vmSpecification);
}
public void testCreateImageMachineFromIso() throws Exception {
+ Injector injector = context.utils().injector();
+ Function<String, String> configProperties = injector.getInstance(ValueOfConfigurationKeyOrNull.class);
- IMachine imageMachine = context.utils().injector().getInstance(CreateAndInstallVm.class).apply(vmSpecification);
+ IMachineSpec machineSpec = IMachineSpec.builder().vm(vmSpecification)
+ .iso(IsoSpec.builder()
+ .sourcePath(operatingSystemIso)
+ .installationScript(configProperties
+ .apply(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE)
+ .replace("HOSTNAME", vmSpecification.getVmName()))
+ .preConfiguration(preconfigurationUri)
+ .build())
+ .network(NetworkSpec.builder()
+ .natNetworkAdapter(0, NatAdapter.builder().tcpRedirectRule("127.0.0.1", 2222, "", 22).build())
+ .build()).build();
+ IMachine imageMachine = injector.getInstance(CreateAndInstallVm.class).apply(machineSpec);
IMachineToImage iMachineToImage = new IMachineToImage(manager, map);
Image newImage = iMachineToImage.apply(imageMachine);
@@ -107,6 +117,7 @@
}
};
}
+
@Override
@AfterClass(groups = "live")
protected void tearDown() throws Exception {
diff --git a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java
index 9f8664d..36bdbe2 100644
--- a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java
+++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java
@@ -21,11 +21,9 @@
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.fail;
+import com.google.inject.Injector;
import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest;
-import org.jclouds.virtualbox.domain.ErrorCode;
-import org.jclouds.virtualbox.domain.HardDisk;
-import org.jclouds.virtualbox.domain.StorageController;
-import org.jclouds.virtualbox.domain.VmSpec;
+import org.jclouds.virtualbox.domain.*;
import org.testng.annotations.Test;
import org.virtualbox_4_1.CleanupMode;
import org.virtualbox_4_1.IMachine;
@@ -47,38 +45,62 @@
super.setupClient();
ideControllerName = "IDE Controller";
mode = CleanupMode.Full;
- ideController = StorageController.builder().name(ideControllerName).bus(StorageBus.IDE).attachISO(0, 0,
- operatingSystemIso).attachHardDisk(
- HardDisk.builder().diskpath(adminDisk).controllerPort(0).deviceSlot(1).build()).attachISO(1, 1,
- guestAdditionsIso).build();
+ ideController = StorageController.builder().name(ideControllerName).bus(StorageBus.IDE)
+ .attachISO(0, 0, operatingSystemIso)
+ .attachHardDisk(HardDisk.builder().diskpath(adminDisk).controllerPort(0).deviceSlot(1).build()).attachISO(1, 1,
+ guestAdditionsIso).build();
}
@Test
public void testCreateNewMachine() throws Exception {
String vmName = "jclouds-test-create-1-node";
- VmSpec launchSpecification = VmSpec.builder().id(vmName).name(vmName).memoryMB(512).controller(ideController)
- .cleanUpMode(mode).osTypeId("Debian").forceOverwrite(true).build();
- undoVm(launchSpecification);
+ VmSpec vmSpec = VmSpec.builder()
+ .id(vmName)
+ .name(vmName)
+ .memoryMB(512)
+ .controller(ideController)
+ .cleanUpMode(mode)
+ .osTypeId("Debian")
+ .forceOverwrite(true).build();
+ IMachineSpec machineSpec = IMachineSpec.builder()
+ .iso(IsoSpec.builder()
+ .sourcePath(operatingSystemIso)
+ .installationScript("")
+ .preConfiguration(preconfigurationUri)
+ .build())
+ .vm(vmSpec)
+ .network(NetworkSpec.builder().build()).build();
+ undoVm(vmSpec);
try {
IMachine debianNode = context.utils().injector().getInstance(
- CreateAndRegisterMachineFromIsoIfNotAlreadyExists.class).apply(launchSpecification);
+ CreateAndRegisterMachineFromIsoIfNotAlreadyExists.class).apply(machineSpec);
IMachine machine = manager.get().getVBox().findMachine(vmName);
assertEquals(debianNode.getName(), machine.getName());
} finally {
- undoVm(launchSpecification);
+ undoVm(vmSpec);
}
}
@Test
public void testCreateNewMachineWithBadOsType() throws Exception {
String vmName = "jclouds-test-create-2-node";
- VmSpec launchSpecification = VmSpec.builder().id(vmName).name(vmName).memoryMB(512).controller(ideController)
- .cleanUpMode(mode).osTypeId("SomeWeirdUnknownOs").forceOverwrite(true).build();
-
- undoVm(launchSpecification);
+ VmSpec vmSpec = VmSpec.builder().id(vmName).name(vmName).memoryMB(512).controller(ideController)
+ .cleanUpMode(mode).osTypeId("SomeWeirdUnknownOs").forceOverwrite(true).build();
+ IsoSpec isoSpec = IsoSpec.builder()
+ .sourcePath(operatingSystemIso)
+ .installationScript("")
+ .preConfiguration(preconfigurationUri)
+ .build();
+ NetworkSpec networkSpec = NetworkSpec.builder().build();
+ IMachineSpec machineSpec = IMachineSpec.builder()
+ .iso(isoSpec)
+ .vm(vmSpec)
+ .network(networkSpec).build();
+ undoVm(vmSpec);
try {
- context.utils().injector().getInstance(CreateAndRegisterMachineFromIsoIfNotAlreadyExists.class).apply(
- launchSpecification);
+ Injector injector = context.utils().injector();
+ injector.getInstance(CreateAndRegisterMachineFromIsoIfNotAlreadyExists.class)
+ .apply(machineSpec);
fail();
} catch (VBoxException e) {
ErrorCode errorCode = ErrorCode.valueOf(e);
@@ -86,7 +108,7 @@
// if osTypeId is not found.
assertEquals(errorCode, ErrorCode.VBOX_E_OBJECT_NOT_FOUND);
} finally {
- undoVm(launchSpecification);
+ undoVm(vmSpec);
}
}
diff --git a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExistsTest.java b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExistsTest.java
index d285e3f..a0918de 100644
--- a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExistsTest.java
+++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExistsTest.java
@@ -27,7 +27,14 @@
import static org.easymock.classextension.EasyMock.replay;
import static org.easymock.classextension.EasyMock.verify;
+import com.google.common.base.Supplier;
+import com.google.inject.Key;
+import com.google.inject.TypeLiteral;
import org.easymock.EasyMock;
+import org.jclouds.virtualbox.Preconfiguration;
+import org.jclouds.virtualbox.domain.IMachineSpec;
+import org.jclouds.virtualbox.domain.IsoSpec;
+import org.jclouds.virtualbox.domain.NetworkSpec;
import org.jclouds.virtualbox.domain.VmSpec;
import org.testng.annotations.Test;
import org.virtualbox_4_1.CleanupMode;
@@ -40,6 +47,8 @@
import com.google.common.base.Suppliers;
+import java.net.URI;
+
/**
* @author Mattias Holmqvist
*/
@@ -51,11 +60,14 @@
VirtualBoxManager manager = createMock(VirtualBoxManager.class);
IVirtualBox vBox = createMock(IVirtualBox.class);
+ Supplier<URI> preconfiguration = createNiceMock(Supplier.class);
String vmName = "jclouds-image-my-ubuntu-image";
-
- VmSpec launchSpecification = VmSpec.builder().id(vmName).name(vmName).osTypeId("").memoryMB(1024).cleanUpMode(
- CleanupMode.Full).build();
-
+ VmSpec vmSpec = VmSpec.builder().id(vmName).name(vmName).osTypeId("").memoryMB(1024).cleanUpMode(
+ CleanupMode.Full).build();
+ IMachineSpec machineSpec = IMachineSpec.builder()
+ .iso(IsoSpec.builder().sourcePath("some.iso").installationScript("").preConfiguration(preconfiguration).build())
+ .vm(vmSpec)
+ .network(NetworkSpec.builder().build()).build();
IMachine createdMachine = createMock(IMachine.class);
ISession session = createMock(ISession.class);
@@ -71,9 +83,9 @@
expect(vBox.findMachine(vmName)).andThrow(vBoxException);
expect(vBox.createMachine(anyString(), eq(vmName), anyString(), anyString(), anyBoolean())).andReturn(
- createdMachine).anyTimes();
+ createdMachine).anyTimes();
vBox.registerMachine(createdMachine);
-
+
expect(vBox.findMachine(vmName)).andReturn(createdMachine).anyTimes();
expect(manager.getSessionObject()).andReturn(session);
expect(session.getMachine()).andReturn(createdMachine);
@@ -81,13 +93,13 @@
createdMachine.setMemorySize(1024l);
createdMachine.saveSettings();
session.unlockMachine();
-
-
+
+
//TODO: this mock test is not finished.
-
+
replay(manager, createdMachine, vBox, session);
- new CreateAndRegisterMachineFromIsoIfNotAlreadyExists(Suppliers.ofInstance(manager), "/tmp/workingDir").apply(launchSpecification);
+ new CreateAndRegisterMachineFromIsoIfNotAlreadyExists(Suppliers.ofInstance(manager), "/tmp/workingDir").apply(machineSpec);
verify(manager, createdMachine, vBox, session);
}
@@ -97,6 +109,7 @@
VirtualBoxManager manager = createNiceMock(VirtualBoxManager.class);
IVirtualBox vBox = createNiceMock(IVirtualBox.class);
+ Supplier<URI> preconfiguration = createNiceMock(Supplier.class);
String vmName = "jclouds-image-my-ubuntu-image";
IMachine registeredMachine = createMock(IMachine.class);
@@ -107,8 +120,16 @@
replay(manager, vBox);
VmSpec launchSpecification = VmSpec.builder().id("").name(vmName).osTypeId("").memoryMB(1024).cleanUpMode(
- CleanupMode.Full).build();
- new CreateAndRegisterMachineFromIsoIfNotAlreadyExists(Suppliers.ofInstance(manager), "/tmp/workingDir").apply(launchSpecification);
+ CleanupMode.Full).build();
+
+ IMachineSpec machineSpec = IMachineSpec.builder()
+ .iso(IsoSpec.builder()
+ .sourcePath("some.iso")
+ .installationScript("dostuff")
+ .preConfiguration(preconfiguration).build())
+ .vm(launchSpecification)
+ .network(NetworkSpec.builder().build()).build();
+ new CreateAndRegisterMachineFromIsoIfNotAlreadyExists(Suppliers.ofInstance(manager), "/tmp/workingDir").apply(machineSpec);
}
@Test(expectedExceptions = VBoxException.class)
@@ -116,6 +137,7 @@
VirtualBoxManager manager = createNiceMock(VirtualBoxManager.class);
IVirtualBox vBox = createNiceMock(IVirtualBox.class);
+ Supplier<URI> preconfiguration = createNiceMock(Supplier.class);
String vmName = "jclouds-image-my-ubuntu-image";
String errorMessage = "VirtualBox error: Soem other VBox error";
@@ -129,12 +151,20 @@
replay(manager, vBox);
VmSpec launchSpecification = VmSpec.builder().id("").name(vmName).osTypeId("").cleanUpMode(CleanupMode.Full)
- .memoryMB(1024).build();
- new CreateAndRegisterMachineFromIsoIfNotAlreadyExists(Suppliers.ofInstance(manager), "/tmp/workingDir").apply(launchSpecification);
+ .memoryMB(1024).build();
+ IMachineSpec machineSpec = IMachineSpec.builder()
+ .iso(IsoSpec.builder()
+ .sourcePath("some.iso")
+ .installationScript("dostuff")
+ .preConfiguration(preconfiguration).build())
+ .vm(launchSpecification)
+ .network(NetworkSpec.builder().build()).build();
+
+ new CreateAndRegisterMachineFromIsoIfNotAlreadyExists(Suppliers.ofInstance(manager), "/tmp/workingDir").apply(machineSpec);
}
private String anyString() {
- return EasyMock.<String> anyObject();
+ return EasyMock.<String>anyObject();
}
}
diff --git a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndDeleteItsMediaTest.java b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndDeleteItsMediaTest.java
index 3946717..b6382fd 100644
--- a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndDeleteItsMediaTest.java
+++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndDeleteItsMediaTest.java
@@ -28,10 +28,7 @@
import java.util.Collections;
import java.util.List;
-import org.jclouds.virtualbox.domain.HardDisk;
-import org.jclouds.virtualbox.domain.NatAdapter;
-import org.jclouds.virtualbox.domain.StorageController;
-import org.jclouds.virtualbox.domain.VmSpec;
+import org.jclouds.virtualbox.domain.*;
import org.testng.annotations.Test;
import org.virtualbox_4_1.CleanupMode;
import org.virtualbox_4_1.IMachine;
@@ -66,8 +63,7 @@
VmSpec vmSpecification = VmSpec.builder().id(vmId).name(vmName).memoryMB(512).osTypeId(osTypeId)
.controller(ideController)
.forceOverwrite(true)
- .cleanUpMode(CleanupMode.Full)
- .natNetworkAdapter(0, NatAdapter.builder().tcpRedirectRule("127.0.0.1", 2222, "", 22).build()).build();
+ .cleanUpMode(CleanupMode.Full).build();
expect(manager.getVBox()).andReturn(vBox).anyTimes();
expect(vBox.findMachine(vmName)).andReturn(registeredMachine);
diff --git a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/IsLinkedClonesLiveTest.java b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/IsLinkedClonesLiveTest.java
index b4a86d8..3459020 100644
--- a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/IsLinkedClonesLiveTest.java
+++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/IsLinkedClonesLiveTest.java
@@ -22,10 +22,9 @@
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
+import com.google.inject.Injector;
import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest;
-import org.jclouds.virtualbox.domain.HardDisk;
-import org.jclouds.virtualbox.domain.StorageController;
-import org.jclouds.virtualbox.domain.VmSpec;
+import org.jclouds.virtualbox.domain.*;
import org.jclouds.virtualbox.functions.CloneAndRegisterMachineFromIMachineIfNotAlreadyExists;
import org.jclouds.virtualbox.functions.CreateAndRegisterMachineFromIsoIfNotAlreadyExists;
import org.testng.annotations.AfterMethod;
@@ -53,7 +52,7 @@
private String cloneName;
private String vmName;
private StorageController masterStorageController;
- private VmSpec masterSpec;
+ private IMachineSpec masterMachineSpec;
private VmSpec cloneSpec;
@Override
@@ -70,8 +69,15 @@
.build();
masterStorageController = StorageController.builder().name(ideControllerName).bus(StorageBus.IDE).attachISO(0, 0,
operatingSystemIso).attachHardDisk(hardDisk).attachISO(1, 1, guestAdditionsIso).build();
- masterSpec = VmSpec.builder().id(vmId).name(vmName).memoryMB(512).osTypeId(osTypeId).controller(
+ VmSpec masterSpec = VmSpec.builder().id(vmId).name(vmName).memoryMB(512).osTypeId(osTypeId).controller(
masterStorageController).forceOverwrite(true).cleanUpMode(CleanupMode.Full).build();
+ masterMachineSpec = IMachineSpec.builder()
+ .iso(IsoSpec.builder()
+ .sourcePath(operatingSystemIso)
+ .preConfiguration(preconfigurationUri)
+ .installationScript("").build())
+ .vm(masterSpec)
+ .network(NetworkSpec.builder().build()).build();
cloneSpec = VmSpec.builder().id(cloneName).name(cloneName).memoryMB(512).cleanUpMode(CleanupMode.Full)
.forceOverwrite(true).build();
@@ -80,8 +86,9 @@
@Test
public void testLinkedClone() {
- IMachine master = context.utils().injector().getInstance(CreateAndRegisterMachineFromIsoIfNotAlreadyExists.class)
- .apply(masterSpec);
+ Injector injector = context.utils().injector();
+ IMachine master = injector.getInstance(CreateAndRegisterMachineFromIsoIfNotAlreadyExists.class)
+ .apply(masterMachineSpec);
IMachine clone = new CloneAndRegisterMachineFromIMachineIfNotAlreadyExists(manager, workingDir, cloneSpec,
IS_LINKED_CLONE).apply(master);
@@ -102,7 +109,7 @@
@BeforeMethod
@AfterMethod
void cleanUpVms() {
- for (VmSpec spec : ImmutableSet.of(cloneSpec, masterSpec))
+ for (VmSpec spec : ImmutableSet.of(cloneSpec, masterMachineSpec.getVmSpec()))
this.undoVm(spec);
}
}
diff --git a/sandbox-providers/dunkel-vcd/pom.xml b/sandbox-providers/dunkel-vcd/pom.xml
index 71d887b..99a564c 100644
--- a/sandbox-providers/dunkel-vcd/pom.xml
+++ b/sandbox-providers/dunkel-vcd/pom.xml
@@ -35,10 +35,12 @@
<properties>
<test.dunkel-vcd.endpoint>https://vcd.dunkel.de/api</test.dunkel-vcd.endpoint>
<test.dunkel-vcd.api-version>1.0</test.dunkel-vcd.api-version>
- <test.dunkel-vcd.build-version></test.dunkel-vcd.build-version>
+ <test.dunkel-vcd.build-version>1.0.1.356485</test.dunkel-vcd.build-version>
<test.dunkel-vcd.identity>FIXME_IDENTITY</test.dunkel-vcd.identity>
<test.dunkel-vcd.credential>FIXME_CREDENTIAL</test.dunkel-vcd.credential>
<test.dunkel-vcd.image-id></test.dunkel-vcd.image-id>
+ <test.dunkel-vcd.image.login-user></test.dunkel-vcd.image.login-user>
+ <test.dunkel-vcd.image.authenticate-sudo></test.dunkel-vcd.image.authenticate-sudo>
</properties>
<dependencies>
@@ -98,14 +100,16 @@
<goal>test</goal>
</goals>
<configuration>
- <systemPropertyVariables>
- <test.dunkel-vcd.endpoint>${test.dunkel-vcd.endpoint}</test.dunkel-vcd.endpoint>
- <test.dunkel-vcd.api-version>${test.dunkel-vcd.api-version}</test.dunkel-vcd.api-version>
- <test.dunkel-vcd.build-version>${test.dunkel-vcd.build-version}</test.dunkel-vcd.build-version>
- <test.dunkel-vcd.identity>${test.dunkel-vcd.identity}</test.dunkel-vcd.identity>
- <test.dunkel-vcd.credential>${test.dunkel-vcd.credential}</test.dunkel-vcd.credential>
- <test.dunkel-vcd.image-id>${test.dunkel-vcd.image-id}</test.dunkel-vcd.image-id>
- </systemPropertyVariables>
+ <systemPropertyVariables>
+ <test.dunkel-vcd.endpoint>${test.dunkel-vcd.endpoint}</test.dunkel-vcd.endpoint>
+ <test.dunkel-vcd.api-version>${test.dunkel-vcd.api-version}</test.dunkel-vcd.api-version>
+ <test.dunkel-vcd.build-version>${test.dunkel-vcd.build-version}</test.dunkel-vcd.build-version>
+ <test.dunkel-vcd.identity>${test.dunkel-vcd.identity}</test.dunkel-vcd.identity>
+ <test.dunkel-vcd.credential>${test.dunkel-vcd.credential}</test.dunkel-vcd.credential>
+ <test.dunkel-vcd.image-id>${test.dunkel-vcd.image-id}</test.dunkel-vcd.image-id>
+ <test.dunkel-vcd.image.login-user>${test.dunkel-vcd.image.login-user}</test.dunkel-vcd.image.login-user>
+ <test.dunkel-vcd.image.authenticate-sudo>${test.dunkel-vcd.image.authenticate-sudo}</test.dunkel-vcd.image.authenticate-sudo>
+ </systemPropertyVariables>
</configuration>
</execution>
</executions>
@@ -115,6 +119,21 @@
</profile>
</profiles>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Export-Package>org.jclouds.dunkel.vcd.*;version="${project.version}"</Export-Package>
+ <Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
</project>
diff --git a/sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/DunkelVCloudDirectorPropertiesBuilder.java b/sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/DunkelVCloudDirectorPropertiesBuilder.java
index fcd3773..29521af 100644
--- a/sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/DunkelVCloudDirectorPropertiesBuilder.java
+++ b/sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/DunkelVCloudDirectorPropertiesBuilder.java
@@ -18,6 +18,7 @@
*/
package org.jclouds.dunkel.vcd;
+import static org.jclouds.Constants.PROPERTY_BUILD_VERSION;
import static org.jclouds.Constants.PROPERTY_ENDPOINT;
import static org.jclouds.Constants.PROPERTY_ISO3166_CODES;
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_NETWORK;
@@ -35,6 +36,7 @@
protected Properties defaultProperties() {
Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_ISO3166_CODES, "DE");
+ properties.setProperty(PROPERTY_BUILD_VERSION, "1.0.1.356485");
properties.setProperty(PROPERTY_ENDPOINT, "https://vcd.dunkel.de/api");
properties.setProperty(PROPERTY_VCLOUD_DEFAULT_NETWORK, ".*-intranet");
return properties;
diff --git a/sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/config/DunkelVCloudDirectorRestClientModule.java b/sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/config/DunkelVCloudDirectorRestClientModule.java
index 9a1e1ed..1c6aba2 100644
--- a/sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/config/DunkelVCloudDirectorRestClientModule.java
+++ b/sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/config/DunkelVCloudDirectorRestClientModule.java
@@ -21,8 +21,6 @@
import org.jclouds.http.RequiresHttp;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.vcloud.config.VCloudRestClientModule;
-import org.jclouds.vcloud.filters.SetVCloudTokenCookie;
-import org.jclouds.dunkel.vcd.filters.SetVCloudTokenCookieAndAuthorizationHeader;
/**
*
@@ -32,10 +30,4 @@
@ConfiguresRestClient
public class DunkelVCloudDirectorRestClientModule extends VCloudRestClientModule {
- @Override
- protected void configure() {
- super.configure();
- bind(SetVCloudTokenCookie.class).to(SetVCloudTokenCookieAndAuthorizationHeader.class);
- }
-
}
diff --git a/sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/filters/SetVCloudTokenCookieAndAuthorizationHeader.java b/sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/filters/SetVCloudTokenCookieAndAuthorizationHeader.java
deleted file mode 100644
index 746d0d5..0000000
--- a/sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/filters/SetVCloudTokenCookieAndAuthorizationHeader.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * 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.dunkel.vcd.filters;
-
-import javax.inject.Inject;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-
-import org.jclouds.http.HttpException;
-import org.jclouds.http.HttpRequest;
-import org.jclouds.http.utils.ModifyRequest;
-import org.jclouds.vcloud.VCloudToken;
-import org.jclouds.vcloud.filters.SetVCloudTokenCookie;
-
-/**
- * Adds the VCloud Token to the request as a cookie
- *
- * @author Adrian Cole
- *
- */
-@Singleton
-public class SetVCloudTokenCookieAndAuthorizationHeader extends SetVCloudTokenCookie {
-
- private final Provider<String> vcloudTokenProvider;
-
- @Inject
- public SetVCloudTokenCookieAndAuthorizationHeader(@VCloudToken Provider<String> authTokenProvider) {
- super(authTokenProvider);
- this.vcloudTokenProvider = authTokenProvider;
- }
-
- @Override
- public HttpRequest filter(HttpRequest request) throws HttpException {
- return ModifyRequest.replaceHeader(super.filter(request), "x-vcloud-authorization", vcloudTokenProvider.get());
- }
-
-}
diff --git a/sandbox-providers/dunkel-vcd/src/test/java/org/jclouds/dunkel/vcd/compute/DunkelVCloudDirectorComputeServiceLiveTest.java b/sandbox-providers/dunkel-vcd/src/test/java/org/jclouds/dunkel/vcd/compute/DunkelVCloudDirectorComputeServiceLiveTest.java
index 2657004..d5e46c8 100644
--- a/sandbox-providers/dunkel-vcd/src/test/java/org/jclouds/dunkel/vcd/compute/DunkelVCloudDirectorComputeServiceLiveTest.java
+++ b/sandbox-providers/dunkel-vcd/src/test/java/org/jclouds/dunkel/vcd/compute/DunkelVCloudDirectorComputeServiceLiveTest.java
@@ -32,9 +32,4 @@
provider = "dunkel-vcd";
}
- @Override
- public void setServiceDefaults() {
- group = "director";
- }
-
}
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Archive.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Archive.java
index 1d87820..cfbb059 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Archive.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Archive.java
@@ -74,18 +74,22 @@
private final String freeSize;
private final boolean locked;
+ /** @return the name (username) of the archive */
public String getUsername() {
return username;
}
+ /** @return the total size of the archive, ex. "10 GB" */
public String getTotalSize() {
return totalSize;
}
+ /** @return the free space left of the archive */
public String getFreeSize() {
return freeSize;
}
+ /** @return true if the archive is locked */
public boolean isLocked() {
return locked;
}
@@ -97,7 +101,6 @@
this.locked = locked;
}
-
@Override
public int hashCode() {
return Objects.hashCode(username);
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Domain.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Domain.java
index bdee0df..5aa645d 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Domain.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Domain.java
@@ -84,18 +84,22 @@
this.glesysNameServer = glesysNameServer;
}
+ /** @return the domain name, ex. "jclouds.org" */
public String getDomain() {
return domain;
}
+ /** @return the date the domain was registered with GleSYS */
public Date getCreateTime() {
return createTime;
}
+ /** @return the number of DNS records for this domain */
public int getRecordCount() {
return recordCount;
}
+ /** @return true if a GleSYS nameserver holds the records */
public boolean getGlesysNameServer() {
return glesysNameServer;
}
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/DomainRecord.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/DomainRecord.java
index 86b4fe6..3ea4896 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/DomainRecord.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/DomainRecord.java
@@ -95,26 +95,45 @@
this.ttl = ttl;
}
+ /**
+ * @return the id of the record used to modify it via the API
+ * @see org.jclouds.glesys.features.DomainClient
+ */
public String getId() {
return id;
}
+ /**
+ * @return the zone content of the record
+ */
public String getZone() {
return zone;
}
+ /**
+ * @return the host content of the record
+ */
public String getHost() {
return host;
}
+ /**
+ * @return the type of the record, ex. "A"
+ */
public String getType() {
return type;
}
+ /**
+ * @return the data content of the record
+ */
public String getData() {
return data;
}
+ /**
+ * @return the TTL/Time-to-live for the record
+ */
public int getTtl() {
return ttl;
}
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Email.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Email.java
index 3846c4e..af6accd 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Email.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Email.java
@@ -139,26 +139,32 @@
this.modified = modified;
}
+ /** @return the e-mail address for this e-mail account */
public String getAccount() {
return account;
}
+ /** @return the quota for this e-mail account */
public String getQuota() {
return quota;
}
+ /** @return the amount of quota currently in use */
public String getUsedQuota() {
return usedQuota;
}
+ /** @return the antispam level of the e-mail account */
public int getAntispamLevel() {
return antispamLevel;
}
+ /** @return true if antivirus is enabled for this e-mail account */
public boolean getAntiVirus() {
return antiVirus;
}
+ /** @return true if auto-respond is enabled for this e-mail account */
public boolean getAutoRespond() {
return autoRespond;
}
@@ -167,14 +173,17 @@
return autoRespondMessage;
}
+ /** @return true if saving is enabled for auto-respond e-mails */
public boolean getAutoRespondSaveEmail() {
return autoRespondSaveEmail;
}
+ /** @return when this account was created */
public Date getCreated() {
return created;
}
+ /** @return when this account was last modified */
public Date getModified() {
return modified;
}
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverview.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverview.java
index 708dcc1..f37ee3d 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverview.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverview.java
@@ -25,6 +25,8 @@
import java.util.Set;
/**
+ * Structure containing all information about e-mail addresses for a GleSYS account
+ *
* @author Adam Lowe
* @see <a href="https://customer.glesys.com/api.php?a=doc#email_overview" />
*/
@@ -68,10 +70,12 @@
this.domains = domains;
}
+ /** @return summary information about the account */
public EmailOverviewSummary getSummary() {
return summary;
}
+ /** @return the set of detailed information about the e-mail addresses and aliases for each domain */
public Set<EmailOverviewDomain> getDomains() {
return domains == null ? ImmutableSet.<EmailOverviewDomain>of() : domains;
}
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewDomain.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewDomain.java
index 0836645..6475bf4 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewDomain.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewDomain.java
@@ -21,6 +21,8 @@
import com.google.common.base.Objects;
/**
+ * Detailed information about e-mail settings for a single domain
+ *
* @author Adam Lowe
* @see <a href="https://customer.glesys.com/api.php?a=doc#email_overview" />
*/
@@ -68,14 +70,17 @@
this.aliases = aliases;
}
+ /** @return the domain name */
public String getDomain() {
return domain;
}
+ /** @return the number of e-mail accounts in the domain */
public int getAccounts() {
return accounts;
}
+ /** @return the number of e-mail aliases in the domain */
public int getAliases() {
return aliases;
}
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewSummary.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewSummary.java
index 06bf114..d8553bd 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewSummary.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewSummary.java
@@ -22,6 +22,8 @@
import com.google.gson.annotations.SerializedName;
/**
+ * Summary information of e-mail settings and limits for a GleSYS account
+ *
* @author Adam Lowe
* @see <a href="https://customer.glesys.com/api.php?a=doc#email_overview" />
*/
@@ -79,18 +81,22 @@
this.maxAliases = maxAliases;
}
+ /** @return the number of e-mail accounts */
public int getAccounts() {
return accounts;
}
+ /** @return the maximum number of e-mail accounts */
public int getMaxAccounts() {
return maxAccounts;
}
+ /** @return the number of e-mail aliases */
public int getAliases() {
return aliases;
}
+ /** @return the maximum number of e-mail aliases */
public int getMaxAliases() {
return maxAliases;
}
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerCreated.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerCreated.java
index 07aa87b..7f02659 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerCreated.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerCreated.java
@@ -30,8 +30,8 @@
import com.google.gson.annotations.SerializedName;
/**
- * Connection information to connect to a server with VNC.
- *
+ * Information about a new server
+ *
* @author Adam Lowe
* @see <a href="https://customer.glesys.com/api.php?a=doc#server_create" />
*/
@@ -44,11 +44,12 @@
private String id;
private String hostname;
private List<ServerCreatedIp> ips;
-
+
public Builder id(String id) {
this.id = id;
return this;
}
+
public Builder ips(List<ServerCreatedIp> ips) {
this.ips = ips;
return this;
@@ -57,16 +58,16 @@
public Builder ips(ServerCreatedIp... ips) {
return ips(Arrays.asList(ips));
}
-
+
public Builder hostname(String hostname) {
this.hostname = hostname;
return this;
}
-
+
public ServerCreated build() {
return new ServerCreated(id, hostname, ips);
}
-
+
public Builder fromServerCreated(ServerCreated in) {
return id(in.getId()).hostname(in.getHostname()).ips(in.getIps());
}
@@ -85,14 +86,20 @@
this.ips = ips;
}
+ /**
+ * @return the id of the server (used for other calls to identify the server.
+ * @see org.jclouds.glesys.features.ServerClient
+ */
public String getId() {
return id;
}
+ /** @return the hostname of the server */
public String getHostname() {
return hostname;
}
+ /** @return the IP addresses assigned to the server */
public List<ServerCreatedIp> getIps() {
return ips == null ? ImmutableList.<ServerCreatedIp>of() : ips;
}
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerDetails.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerDetails.java
index e8347bf..4622233 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerDetails.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerDetails.java
@@ -111,7 +111,7 @@
public ServerDetails(String id, String hostname, String datacenter, String platform, String description,
int cpuCores, int memory, int disk, Cost cost) {
super(id, hostname, datacenter, platform);
- this.description = checkNotNull(description, "description");
+ this.description = description;
this.cpuCores = cpuCores;
this.memory = memory;
this.disk = disk;
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerStatus.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerStatus.java
index 9e802c3..8b8d01c 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerStatus.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerStatus.java
@@ -150,7 +150,7 @@
&& Objects.equal(memory, other.memory)
&& Objects.equal(disk, other.disk)
&& Objects.equal(bandwidth, other.bandwidth)
- && uptime == other.uptime;
+ && Objects.equal(uptime, other.uptime);
} else {
return false;
}
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerUptime.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerUptime.java
index 24ab2a9..7eefe11 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerUptime.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerUptime.java
@@ -81,6 +81,9 @@
return new ServerUptime(time);
}
+ /**
+ * @return the number of seconds the server has been up
+ */
public long getTime() {
return time;
}
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ArchiveAsyncClient.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ArchiveAsyncClient.java
index 4098ebe..f79a77f 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ArchiveAsyncClient.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ArchiveAsyncClient.java
@@ -99,7 +99,7 @@
@Path("/archive/allowedarguments/format/json")
@SelectJson("argumentslist")
@Consumes(MediaType.APPLICATION_JSON)
- @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
+ @ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<ArchiveAllowedArguments> getArchiveAllowedArguments();
}
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/DomainAsyncClient.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/DomainAsyncClient.java
index c0ba9e5..d719a24 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/DomainAsyncClient.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/DomainAsyncClient.java
@@ -21,9 +21,10 @@
import com.google.common.util.concurrent.ListenableFuture;
import org.jclouds.glesys.domain.Domain;
import org.jclouds.glesys.domain.DomainRecord;
+import org.jclouds.glesys.options.DomainAddOptions;
import org.jclouds.glesys.options.DomainOptions;
import org.jclouds.glesys.options.DomainRecordAddOptions;
-import org.jclouds.glesys.options.DomainRecordModifyOptions;
+import org.jclouds.glesys.options.DomainRecordEditOptions;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.RequestFilters;
@@ -63,7 +64,7 @@
*/
@POST
@Path("/domain/add/format/json")
- ListenableFuture<Void> addDomain(@FormParam("name") String name, DomainOptions... options);
+ ListenableFuture<Void> addDomain(@FormParam("name") String name, DomainAddOptions... options);
/**
* @see DomainClient#editDomain
@@ -72,26 +73,42 @@
@Path("/domain/edit/format/json")
ListenableFuture<Void> editDomain(@FormParam("domain") String domain, DomainOptions... options);
+
+ /**
+ * @see DomainClient#deleteDomain
+ */
@POST
@Path("/domain/delete/format/json")
ListenableFuture<Void> deleteDomain(@FormParam("domain") String domain);
+ /**
+ * @see DomainClient#listRecords
+ */
@POST
@Path("/domain/list_records/format/json")
@SelectJson("records")
@Consumes(MediaType.APPLICATION_JSON)
ListenableFuture<Set<DomainRecord>> listRecords(@FormParam("domain") String domain);
+ /**
+ * @see DomainClient#addRecord
+ */
@POST
@Path("/domain/add_record/format/json")
ListenableFuture<Void> addRecord(@FormParam("domain") String domain, @FormParam("host") String host,
@FormParam("type") String type, @FormParam("data") String data,
DomainRecordAddOptions... options);
+ /**
+ * @see DomainClient#editRecord
+ */
@POST
@Path("/domain/update_record/format/json")
- ListenableFuture<Void> editRecord(@FormParam("record_id") String record_id, DomainRecordModifyOptions... options);
+ ListenableFuture<Void> editRecord(@FormParam("record_id") String record_id, DomainRecordEditOptions... options);
+ /**
+ * @see DomainClient#deleteRecord
+ */
@POST
@Path("/domain/delete_record/format/json")
ListenableFuture<Void> deleteRecord(@FormParam("record_id") String recordId);
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/DomainClient.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/DomainClient.java
index 80d0b3e..f02a776 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/DomainClient.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/DomainClient.java
@@ -21,15 +21,16 @@
import org.jclouds.concurrent.Timeout;
import org.jclouds.glesys.domain.Domain;
import org.jclouds.glesys.domain.DomainRecord;
+import org.jclouds.glesys.options.DomainAddOptions;
import org.jclouds.glesys.options.DomainOptions;
import org.jclouds.glesys.options.DomainRecordAddOptions;
-import org.jclouds.glesys.options.DomainRecordModifyOptions;
+import org.jclouds.glesys.options.DomainRecordEditOptions;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
- * Provides synchronous access to Invoice requests.
+ * Provides synchronous access to Domain requests.
* <p/>
*
* @author Adam Lowe
@@ -52,7 +53,7 @@
* @param domain the name of the domain to add.
* @param options optional parameters
*/
- void addDomain(String domain, DomainOptions... options);
+ void addDomain(String domain, DomainAddOptions... options);
/**
* Add a domain to the Glesys dns-system
@@ -94,7 +95,7 @@
* @param options the settings to change
* @see #listRecords to retrieve the necessary ids
*/
- void editRecord(String recordId, DomainRecordModifyOptions... options);
+ void editRecord(String recordId, DomainRecordEditOptions... options);
/**
* Delete a DNS record
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailAsyncClient.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailAsyncClient.java
index 7d88a81..ed30390 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailAsyncClient.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailAsyncClient.java
@@ -37,6 +37,7 @@
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import com.google.common.util.concurrent.ListenableFuture;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
/**
* Provides asynchronous access to E-Mail data via the Glesys REST API.
@@ -50,13 +51,13 @@
public interface EmailAsyncClient {
/**
- * @see org.jclouds.glesys.features.EmailClient#emailOverview
+ * @see org.jclouds.glesys.features.EmailClient#getEmailOverview
*/
@POST
@Path("/email/overview/format/json")
@SelectJson("response")
@Consumes(MediaType.APPLICATION_JSON)
- @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
+ @ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<EmailOverview> getEmailOverview();
/**
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailClient.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailClient.java
index b2304e4..f7d75b3 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailClient.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailClient.java
@@ -32,7 +32,7 @@
* <p/>
*
* @author Adam Lowe
- * @see org.jclouds.glesys.features.DomainAsyncClient
+ * @see org.jclouds.glesys.features.EmailAsyncClient
* @see <a href="https://customer.glesys.com/api.php" />
*/
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
@@ -46,19 +46,52 @@
EmailOverview getEmailOverview();
/**
- *
- * @return
+ * Get the set of detailed information about e-mail accounts
+ *
+ * @return the relevant set of details
*/
Set<Email> listAccounts(String domain);
+ /**
+ * Create a new e-mail account
+ *
+ * @param accountAddress the e-mail address to use (the domain should already exist)
+ * @param password the password to use for the mailbox
+ * @param options optional parameters
+ * @see DomainClient#addDomain
+ */
void createAccount(String accountAddress, String password, EmailCreateOptions... options);
+ /**
+ * Create an e-mail alias for an e-mail account
+ *
+ * @param aliasAddress the address to use for the alias (the domain should already exist)
+ * @param toEmailAddress the existing e-mail account address the alias should forward to
+ * @see DomainClient#addDomain
+ */
void createAlias(String aliasAddress, String toEmailAddress);
+ /**
+ * Adjust an e-mail account's settings
+ *
+ * @param accountAddress the existing e-mail account address
+ * @param options optional parameters
+ */
void editAccount(String accountAddress, EmailEditOptions... options);
-
+
+ /**
+ * Adjust (re-target) an e-mail alias
+ *
+ * @param aliasAddress the existing alias e-mail address
+ * @param toEmailAddress the existing e-mail account address the alias should forward to
+ */
void editAlias(String aliasAddress, String toEmailAddress);
+ /**
+ * Delete an e-mail account or alias
+ *
+ * @param accountAddress the existing alias e-mail account or alias address
+ */
void delete(String accountAddress);
}
\ No newline at end of file
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ServerClient.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ServerClient.java
index 8d0b966..251d1a3 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ServerClient.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ServerClient.java
@@ -100,9 +100,9 @@
/**
* Get information about the OS templates available
*
- * @return a map of templates, keyed on platform
+ * @return the set of information about each template
*/
- Map<String, Set<ServerTemplate>> getTemplates();
+ Set<ServerTemplate> getTemplates();
/**
* Get information about valid arguments to #createServer for each platform
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainAddOptions.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainAddOptions.java
new file mode 100644
index 0000000..645b597
--- /dev/null
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainAddOptions.java
@@ -0,0 +1,93 @@
+/**
+ * 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.glesys.options;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * @author Adam Lowe
+ */
+public class DomainAddOptions extends DomainOptions {
+ public static class Builder {
+ /**
+ * @see DomainAddOptions#primaryNameServer
+ */
+ public static DomainAddOptions primaryNameServer(String primaryNameServer) {
+ return DomainAddOptions.class.cast(new DomainAddOptions().primaryNameServer(primaryNameServer));
+ }
+
+ /**
+ * @see DomainAddOptions#responsiblePerson
+ */
+ public static DomainAddOptions responsiblePerson(String responsiblePerson) {
+ return DomainAddOptions.class.cast(new DomainAddOptions().responsiblePerson(responsiblePerson));
+ }
+
+ /**
+ * @see DomainAddOptions#ttl
+ */
+ public static DomainAddOptions ttl(int ttl) {
+ return DomainAddOptions.class.cast(new DomainAddOptions().ttl(ttl));
+ }
+
+ /**
+ * @see DomainAddOptions#refresh
+ */
+ public static DomainAddOptions refresh(int refresh) {
+ return DomainAddOptions.class.cast(new DomainAddOptions().refresh(refresh));
+ }
+
+ /**
+ * @see DomainAddOptions#retry
+ */
+ public static DomainAddOptions retry(int retry) {
+ return DomainAddOptions.class.cast(new DomainAddOptions().retry(retry));
+ }
+
+ /**
+ * @see DomainAddOptions#expire
+ */
+ public static DomainAddOptions expire(int expire) {
+ return DomainAddOptions.class.cast(new DomainAddOptions().expire(expire));
+ }
+
+ /**
+ * @see DomainAddOptions#minimum
+ */
+ public static DomainAddOptions minimum(int minimum) {
+ return DomainAddOptions.class.cast(new DomainAddOptions().minimum(minimum));
+ }
+
+ /**
+ * @see DomainAddOptions#minimalRecords
+ */
+ public static DomainAddOptions minimalRecords() {
+ return DomainAddOptions.class.cast(new DomainAddOptions().minimalRecords());
+ }
+ }
+
+ /**
+ * Ensure only NS and SOA records will be created by default, when this option is not used a number of default records will be created on the domain.
+ */
+ public DomainOptions minimalRecords() {
+ formParameters.put("create_records", "0");
+ return this;
+ }
+
+}
\ No newline at end of file
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainOptions.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainOptions.java
index 6bc47aa..c2f6e80 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainOptions.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainOptions.java
@@ -52,7 +52,7 @@
/**
* @see DomainOptions#refresh
*/
- public static DomainOptions refresh(String refresh) {
+ public static DomainOptions refresh(int refresh) {
DomainOptions options = new DomainOptions();
return options.refresh(refresh);
}
@@ -60,7 +60,7 @@
/**
* @see DomainOptions#retry
*/
- public static DomainOptions retry(String retry) {
+ public static DomainOptions retry(int retry) {
DomainOptions options = new DomainOptions();
return options.retry(retry);
}
@@ -68,7 +68,7 @@
/**
* @see DomainOptions#expire
*/
- public static DomainOptions expire(String expire) {
+ public static DomainOptions expire(int expire) {
DomainOptions options = new DomainOptions();
return options.expire(expire);
}
@@ -76,44 +76,71 @@
/**
* @see DomainOptions#minimum
*/
- public static DomainOptions minimum(String minimum) {
+ public static DomainOptions minimum(int minimum) {
DomainOptions options = new DomainOptions();
return options.minimum(minimum);
}
}
+ /**
+ * Configure the primary DNS server for this domain.
+ */
public DomainOptions primaryNameServer(String primaryNameServer) {
formParameters.put("primary_ns", primaryNameServer);
return this;
}
+ /**
+ * Configure the E-mail address of the person responsible for this domain (usually attached to MX records).
+ */
public DomainOptions responsiblePerson(String responsiblePerson) {
+ responsiblePerson = responsiblePerson.replaceAll("@", ".");
+ if (!responsiblePerson.endsWith(".")) {
+ responsiblePerson = responsiblePerson + ".";
+ }
formParameters.put("resp_person", responsiblePerson);
return this;
}
+ /**
+ * TTL (time to live). The number of seconds a domain name is cached locally before expiration and return to authoritative nameservers for updates
+ */
public DomainOptions ttl(int ttl) {
formParameters.put("ttl", Integer.toString(ttl));
return this;
}
- public DomainOptions refresh(String refresh) {
- formParameters.put("refresh", refresh);
+ /**
+ * Configure the number of seconds between update requests from secondary and slave name servers
+ */
+ public DomainOptions refresh(int refresh) {
+ formParameters.put("refresh", Integer.toString(refresh));
return this;
}
- public DomainOptions retry(String retry) {
- formParameters.put("retry", retry);
+ /**
+ * Configure the number of seconds the secondary/slave will wait before retrying when the last attempt failed
+ */
+ public DomainOptions retry(int retry) {
+ formParameters.put("retry", Integer.toString(retry));
return this;
}
- public DomainOptions expire(String expire) {
- formParameters.put("primary_ns", expire);
+ /**
+ * Configure the number of seconds a master or slave will wait before considering the data stale if it cannot reach the primary name server
+ */
+ public DomainOptions expire(int expire) {
+ formParameters.put("expire", Integer.toString(expire));
return this;
}
- public DomainOptions minimum(String minimum) {
- formParameters.put("minimum", minimum);
+ /**
+ * Configure the minimum/default TTL if the domain does not specify ttl
+ *
+ * @see #ttl
+ */
+ public DomainOptions minimum(int minimum) {
+ formParameters.put("minimum", Integer.toString(minimum));
return this;
}
}
\ No newline at end of file
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordAddOptions.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordAddOptions.java
index fc304b8..281cfbd 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordAddOptions.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordAddOptions.java
@@ -37,24 +37,21 @@
/**
* @see DomainRecordAddOptions#mxPriority
*/
- public static DomainRecordAddOptions mxPriority(String mxPriority) {
+ public static DomainRecordAddOptions mxPriority(int mxPriority) {
DomainRecordAddOptions options = new DomainRecordAddOptions();
return options.mxPriority(mxPriority);
}
}
- public DomainRecordAddOptions host(String host) {
- formParameters.put("host", host);
- return this;
- }
-
+ /** Configure TTL/Time-to-live for record */
public DomainRecordAddOptions ttl(int ttl) {
formParameters.put("ttl", Integer.toString(ttl));
return this;
}
- public DomainRecordAddOptions mxPriority(String mxPriority) {
- formParameters.put("mx_priority", mxPriority);
+ /** Configure the priority of an MX record */
+ public DomainRecordAddOptions mxPriority(int mxPriority) {
+ formParameters.put("mx_priority", Integer.toString(mxPriority));
return this;
}
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordEditOptions.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordEditOptions.java
new file mode 100644
index 0000000..60b8cde
--- /dev/null
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordEditOptions.java
@@ -0,0 +1,81 @@
+/**
+ * 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.glesys.options;
+
+/**
+ * @author Adam Lowe
+ */
+public class DomainRecordEditOptions extends DomainRecordAddOptions {
+
+ public static class Builder {
+ /**
+ * @see DomainRecordEditOptions#host
+ */
+ public static DomainRecordEditOptions host(String host) {
+ return new DomainRecordEditOptions().host(host);
+ }
+
+ /**
+ * @see DomainRecordEditOptions#type
+ */
+ public static DomainRecordEditOptions type(String type) {
+ return new DomainRecordEditOptions().type(type);
+ }
+
+ /**
+ * @see DomainRecordEditOptions#data
+ */
+ public static DomainRecordEditOptions data(String data) {
+ return new DomainRecordEditOptions().data(data);
+ }
+
+ /**
+ * @see DomainRecordEditOptions#ttl
+ */
+ public static DomainRecordEditOptions ttl(int ttl) {
+ return DomainRecordEditOptions.class.cast(new DomainRecordEditOptions().ttl(ttl));
+ }
+
+ /**
+ * @see DomainRecordEditOptions#mxPriority
+ */
+ public static DomainRecordEditOptions mxPriority(int mxPriority) {
+ return DomainRecordEditOptions.class.cast(new DomainRecordEditOptions().mxPriority(mxPriority));
+ }
+ }
+
+
+ /** Configure the hostname attached to this record */
+ public DomainRecordEditOptions host(String host) {
+ formParameters.put("host", host);
+ return this;
+ }
+
+ /** Configure the type of record, ex. "A", "CNAME" or "MX" */
+ public DomainRecordEditOptions type(String type) {
+ formParameters.put("type", type);
+ return this;
+ }
+
+ /** Set the content of this record (depending on type, for an "A" record this would be an ip address) */
+ public DomainRecordEditOptions data(String data) {
+ formParameters.put("data", data);
+ return this;
+ }
+}
\ No newline at end of file
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordModifyOptions.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordModifyOptions.java
deleted file mode 100644
index 50e46d9..0000000
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordModifyOptions.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
- * 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.glesys.options;
-
-/**
- * @author Adam Lowe
- */
-public class DomainRecordModifyOptions extends DomainRecordAddOptions {
-
- public static class Builder {
- /**
- * @see org.jclouds.glesys.options.DomainRecordAddOptions#host
- */
- public static DomainRecordModifyOptions host(String host) {
- DomainRecordModifyOptions options = new DomainRecordModifyOptions();
- return options.host(host);
- }
-
- /**
- * @see org.jclouds.glesys.options.DomainRecordModifyOptions#type
- */
- public static DomainRecordModifyOptions type(String type) {
- DomainRecordModifyOptions options = new DomainRecordModifyOptions();
- return options.type(type);
- }
-
- /**
- * @see org.jclouds.glesys.options.DomainRecordModifyOptions#data
- */
- public static DomainRecordModifyOptions data(String data) {
- DomainRecordModifyOptions options = new DomainRecordModifyOptions();
- return options.data(data);
- }
-
- /**
- * @see org.jclouds.glesys.options.DomainRecordModifyOptions#ttl
- */
- public static DomainRecordModifyOptions ttl(int ttl) {
- DomainRecordModifyOptions options = new DomainRecordModifyOptions();
- return DomainRecordModifyOptions.class.cast(options.ttl(ttl));
- }
-
- /**
- * @see org.jclouds.glesys.options.DomainRecordModifyOptions#mxPriority
- */
- public static DomainRecordModifyOptions mxPriority(String mxPriority) {
- DomainRecordModifyOptions options = new DomainRecordModifyOptions();
- return DomainRecordModifyOptions.class.cast(options.mxPriority(mxPriority));
- }
- }
-
- public DomainRecordModifyOptions host(String host) {
- formParameters.put("host", host);
- return this;
- }
-
-
- public DomainRecordModifyOptions type(String type) {
- formParameters.put("type", type);
- return this;
- }
-
- public DomainRecordModifyOptions data(String data) {
- formParameters.put("data", data);
- return this;
- }
-}
\ No newline at end of file
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/EmailCreateOptions.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/EmailCreateOptions.java
index b253f6c..a3c74ca 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/EmailCreateOptions.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/EmailCreateOptions.java
@@ -57,33 +57,38 @@
/**
* @see EmailCreateOptions#autorespondMessage
*/
- public static EmailCreateOptions autorespondMessage(boolean autorespondMessage) {
+ public static EmailCreateOptions autorespondMessage(String autorespondMessage) {
return new EmailCreateOptions().autorespondMessage(autorespondMessage);
}
}
+ /** Configure the antispam level of the account */
public EmailCreateOptions antispamLevel(int antispamLevel) {
formParameters.put("antispamlevel", Integer.toString(antispamLevel));
return this;
}
+ /** Enable or disable virus checking */
public EmailCreateOptions antiVirus(boolean antiVirus) {
formParameters.put("antivirus", Integer.toString(antiVirus ? 1 : 0));
return this;
}
+ /** Enable or disable auto-respond */
public EmailCreateOptions autorespond(boolean autorespond) {
formParameters.put("autorespond", Integer.toString(autorespond ? 1 : 0));
return this;
}
+ /** Enable or disable saving of auto-respond e-mails */
public EmailCreateOptions autorespondSaveEmail(boolean autorespondSaveEmail) {
formParameters.put("autorespondsaveemail", Integer.toString(autorespondSaveEmail ? 1 : 0));
return this;
}
- public EmailCreateOptions autorespondMessage(boolean autorespondMessage) {
- formParameters.put("autorespondmessage", Integer.toString(autorespondMessage ? 1 : 0));
+ /** Configure the auto-respond message */
+ public EmailCreateOptions autorespondMessage(String autorespondMessage) {
+ formParameters.put("autorespondmessage", autorespondMessage);
return this;
}
}
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/EmailEditOptions.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/EmailEditOptions.java
index 97f0e90..7e07600 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/EmailEditOptions.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/EmailEditOptions.java
@@ -26,31 +26,50 @@
public class EmailEditOptions extends EmailCreateOptions {
public static class Builder {
+ /**
+ * @see org.jclouds.glesys.options.EmailEditOptions#antispamLevel
+ */
public static EmailEditOptions antispamLevel(int antispamLevel) {
return EmailEditOptions.class.cast(new EmailEditOptions().antispamLevel(antispamLevel));
}
+ /**
+ * @see org.jclouds.glesys.options.EmailEditOptions#antiVirus
+ */
public static EmailEditOptions antiVirus(boolean antiVirus) {
return EmailEditOptions.class.cast(new EmailEditOptions().antiVirus(antiVirus));
}
+ /**
+ * @see org.jclouds.glesys.options.EmailEditOptions#autorespond
+ */
public static EmailEditOptions autorespond(boolean autorespond) {
return EmailEditOptions.class.cast(new EmailEditOptions().autorespond(autorespond));
}
+ /**
+ * @see org.jclouds.glesys.options.EmailEditOptions#autorespondSaveEmail
+ */
public static EmailEditOptions autorespondSaveEmail(boolean autorespondSaveEmail) {
return EmailEditOptions.class.cast(new EmailEditOptions().autorespondSaveEmail(autorespondSaveEmail));
}
- public static EmailEditOptions autorespondMessage(boolean autorespondMessage) {
+ /**
+ * @see org.jclouds.glesys.options.EmailEditOptions#autorespondMessage
+ */
+ public static EmailEditOptions autorespondMessage(String autorespondMessage) {
return EmailEditOptions.class.cast(new EmailEditOptions().autorespondMessage(autorespondMessage));
}
- public static EmailEditOptions autorespondMessage(String password) {
+ /**
+ * @see org.jclouds.glesys.options.EmailEditOptions#password
+ */
+ public static EmailEditOptions password(String password) {
return new EmailEditOptions().password(password);
}
}
+ /** Reset the password for this account */
public EmailEditOptions password(String password) {
formParameters.put("password", password);
return this;
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/ServerCloneOptions.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/ServerCloneOptions.java
index 388a49d..99997e0 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/ServerCloneOptions.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/ServerCloneOptions.java
@@ -27,59 +27,48 @@
* @see org.jclouds.glesys.options.ServerCloneOptions#disksize
*/
public static ServerCloneOptions disksize(int disksize) {
- ServerCloneOptions options = new ServerCloneOptions();
- return ServerCloneOptions.class.cast(options.disksize(disksize));
+ return ServerCloneOptions.class.cast(new ServerCloneOptions().disksize(disksize));
}
/**
* @see org.jclouds.glesys.options.ServerCloneOptions#memorysize
*/
public static ServerCloneOptions memorysize(int memorysize) {
- ServerCloneOptions options = new ServerCloneOptions();
- return ServerCloneOptions.class.cast(options.memorysize(memorysize));
+ return ServerCloneOptions.class.cast(new ServerCloneOptions().memorysize(memorysize));
}
/**
* @see org.jclouds.glesys.options.ServerCloneOptions#cpucores
*/
public static ServerCloneOptions cpucores(int cpucores) {
- ServerCloneOptions options = new ServerCloneOptions();
- return ServerCloneOptions.class.cast(options.cpucores(cpucores));
+ return ServerCloneOptions.class.cast(new ServerCloneOptions().cpucores(cpucores));
}
/**
* @see org.jclouds.glesys.options.ServerCloneOptions#cpucores
*/
public static ServerCloneOptions transfer(int transfer) {
- ServerCloneOptions options = new ServerCloneOptions();
- return ServerCloneOptions.class.cast(options.transfer(transfer));
- }
-
- /**
- * @see org.jclouds.glesys.options.ServerCloneOptions#hostname
- */
- public static ServerCloneOptions hostname(String hostname) {
- ServerCloneOptions options = new ServerCloneOptions();
- return ServerCloneOptions.class.cast(options.hostname(hostname));
+ return ServerCloneOptions.class.cast(new ServerCloneOptions().transfer(transfer));
}
/**
* @see org.jclouds.glesys.options.ServerEditOptions#description
*/
public static ServerCloneOptions description(String description) {
- ServerCloneOptions options = new ServerCloneOptions();
- return ServerCloneOptions.class.cast(options.description(description));
+ return ServerCloneOptions.class.cast(new ServerCloneOptions().description(description));
}
/**
* @see org.jclouds.glesys.options.ServerCloneOptions#dataCenter
*/
public static ServerCloneOptions dataCenter(String dataCenter) {
- ServerCloneOptions options = new ServerCloneOptions();
- return options.dataCenter(dataCenter);
+ return new ServerCloneOptions().dataCenter(dataCenter);
}
}
+ /**
+ * Configure which datacenter to create the clone in
+ */
public ServerCloneOptions dataCenter(String dataCenter) {
formParameters.put("datacenter", dataCenter);
return this;
diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/ServerEditOptions.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/ServerEditOptions.java
index b45070b..ba8a0ff 100644
--- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/ServerEditOptions.java
+++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/ServerEditOptions.java
@@ -76,31 +76,37 @@
}
}
+ /** Configure the size of the disk, in GB, of the server */
public ServerEditOptions disksize(int disksize) {
formParameters.put("disksize", Integer.toString(disksize));
return this;
}
+ /** Configure the amount of RAM, in MB, allocated to the server */
public ServerEditOptions memorysize(int memorysize) {
formParameters.put("memorysize", Integer.toString(memorysize));
return this;
}
+ /** Configure the number of CPU cores allocated to the server */
public ServerEditOptions cpucores(int cpucores) {
formParameters.put("cpucores", Integer.toString(cpucores));
return this;
}
+ /** Configure the transfer setting for the server */
public ServerEditOptions transfer(int transfer) {
formParameters.put("cpucores", Integer.toString(transfer));
return this;
}
+ /** Configure the host name of the server (must be unique within the GleSYS account) */
public ServerEditOptions hostname(String hostname) {
formParameters.put("hostname", hostname);
return this;
}
+ /** Configure the description of the server */
public ServerEditOptions description(String description) {
formParameters.put("description", description);
return this;
diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveAsyncClientTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveAsyncClientTest.java
deleted file mode 100644
index 124f4ec..0000000
--- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveAsyncClientTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * 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.glesys.features;
-
-import java.util.Map;
-
-import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
-import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
-import org.jclouds.rest.internal.RestAnnotationProcessor;
-import org.testng.annotations.Test;
-
-import com.google.inject.TypeLiteral;
-
-/**
- * Tests annotation parsing of {@code ArchiveAsyncClient}
- *
- * @author Adam Lowe
- */
-@Test(groups = "unit", testName = "ArchiveAsyncClientTest")
-public class ArchiveAsyncClientTest extends BaseGleSYSAsyncClientTest<ArchiveAsyncClient> {
- public ArchiveAsyncClientTest() {
- asyncClientClass = ArchiveAsyncClient.class;
- remoteServicePrefix = "archive";
- }
-
- private Map.Entry<String, String> userName = newEntry("username", "x");
-
- public void testListArchives() throws Exception {
- testMethod("listArchives", "list", "POST", true, ReturnEmptySetOnNotFoundOr404.class);
- }
-
- public void testArchiveDetails() throws Exception {
- testMethod("getArchiveDetails", "details", "POST", true, ReturnNullOnNotFoundOr404.class, userName);
- }
-
- public void testCreateArchive() throws Exception {
- testMethod("createArchive", "create", "POST", false, MapHttp4xxCodesToExceptions.class, userName,
- newEntry("password", "somepass"), newEntry("size", 5));
- }
-
- public void testDeleteArchive() throws Exception {
- testMethod("deleteArchive", "delete", "POST", false, MapHttp4xxCodesToExceptions.class, userName);
- }
-
- public void testResizeArchive() throws Exception {
- testMethod("resizeArchive", "resize", "POST", false, MapHttp4xxCodesToExceptions.class, userName,
- newEntry("size", "5 GB"));
- }
-
- public void testChangeArchivePassword() throws Exception {
- testMethod("changeArchivePassword", "changepassword", "POST", false, MapHttp4xxCodesToExceptions.class, userName,
- newEntry("password", "newpass"));
- }
-
- public void testGetArchiveAllowedArguments() throws Exception {
- testMethod("getArchiveAllowedArguments", "allowedarguments", "GET", true, ReturnEmptySetOnNotFoundOr404.class);
- }
-
- @Override
- protected TypeLiteral<RestAnnotationProcessor<ArchiveAsyncClient>> createTypeLiteral() {
- return new TypeLiteral<RestAnnotationProcessor<ArchiveAsyncClient>>() {
- };
- }
-}
diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveClientExpectTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveClientExpectTest.java
new file mode 100644
index 0000000..c0e4875
--- /dev/null
+++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveClientExpectTest.java
@@ -0,0 +1,224 @@
+/**
+ * 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.glesys.features;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMultimap;
+import org.jclouds.glesys.GleSYSClient;
+import org.jclouds.glesys.domain.Archive;
+import org.jclouds.glesys.domain.ArchiveAllowedArguments;
+import org.jclouds.glesys.domain.ArchiveDetails;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+import org.jclouds.rest.BaseRestClientExpectTest;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.testng.annotations.Test;
+
+import java.net.URI;
+import java.util.List;
+
+import static org.jclouds.io.Payloads.newUrlEncodedFormPayload;
+import static org.testng.Assert.*;
+
+/**
+ * Tests parsing of {@code ArchiveAsyncClient}
+ *
+ * @author Adam Lowe
+ */
+@Test(groups = "unit", testName = "ArchiveClientExpectTest")
+public class ArchiveClientExpectTest extends BaseRestClientExpectTest<GleSYSClient> {
+ public ArchiveClientExpectTest() {
+ provider = "glesys";
+ }
+
+ public void testListArchivesWhenReponseIs2xx() throws Exception {
+ ArchiveClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/archive/list/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .build(),
+ HttpResponse.builder().statusCode(200).payload(payloadFromResource("/archive_list.json")).build())
+ .getArchiveClient();
+
+ List<Archive> expected = ImmutableList.<Archive>of(
+ Archive.builder().username("xxxxx_test1").freeSize("20 GB").totalSize("20 GB").locked(false).build());
+
+ assertEquals(client.listArchives(), expected);
+ }
+
+ public void testListArchivesWhenResponseIs4xxReturnsEmpty() {
+ ArchiveClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/archive/list/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()).build(),
+ HttpResponse.builder().statusCode(404).build()).getArchiveClient();
+
+ assertTrue(client.listArchives().isEmpty());
+ }
+
+ public void testArchiveDetailsWhenResponseIs2xx() throws Exception {
+ ArchiveClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/archive/details/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(
+ ImmutableMultimap.<String, String>builder().put("username", "xxxxxx_test1").build())).build(),
+ HttpResponse.builder().statusCode(200).payload(payloadFromResource("/archive_details.json")).build())
+ .getArchiveClient();
+ ArchiveDetails expected = ArchiveDetails.builder().username("xxxxxx_test1").freeSize("30 GB").totalSize("30 GB").locked(false).build();
+
+ assertEquals(client.getArchiveDetails("xxxxxx_test1"), expected);
+ }
+
+ public void testArchiveDetailsWhenResponseIs4xxReturnsNull() {
+ ArchiveClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/archive/details/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(
+ ImmutableMultimap.<String, String>builder().put("username", "xxxxxx_test1").build())).build(),
+ HttpResponse.builder().statusCode(404).build())
+ .getArchiveClient();
+ assertNull(client.getArchiveDetails("xxxxxx_test1"));
+ }
+
+ public void testCreateArchiveWhenResponseIs2xx() throws Exception {
+ ArchiveClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/archive/create/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder().put(
+ "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("username", "xxxxxx_test1")
+ .put("size", "5")
+ .put("password", "somepass").build())).build(),
+ HttpResponse.builder().statusCode(200).build()).getArchiveClient();
+ client.createArchive("xxxxxx_test1", "somepass", 5);
+ }
+
+ public void testDeleteArchiveWhenResponseIs2xx() throws Exception {
+ ArchiveClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/archive/delete/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder().put(
+ "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("username", "xxxxxx_test1").build())).build(),
+ HttpResponse.builder().statusCode(200).build()).getArchiveClient();
+
+ client.deleteArchive("xxxxxx_test1");
+ }
+
+ @Test(expectedExceptions = {HttpResponseException.class})
+ public void testDeleteArchiveWhenResponseIs4xxThrows() throws Exception {
+ ArchiveClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/archive/delete/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder().put(
+ "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("username", "xxxxxx_test1").build())).build(),
+ HttpResponse.builder().statusCode(402).build()).getArchiveClient();
+ client.deleteArchive("xxxxxx_test1");
+ }
+
+ public void testResizeArchiveWhenResponseIs2xx() throws Exception {
+ ArchiveClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/archive/resize/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder().put(
+ "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("username", "username1")
+ .put("size", "5").build())).build(),
+ HttpResponse.builder().statusCode(200).build()).getArchiveClient();
+
+ client.resizeArchive("username1", 5);
+ }
+
+ @Test(expectedExceptions = {ResourceNotFoundException.class})
+ public void testResizeArchiveWhenResponseIs4xxThrows() throws Exception {
+ ArchiveClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/archive/resize/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder().put(
+ "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("username", "username1")
+ .put("size", "5").build())).build(),
+ HttpResponse.builder().statusCode(404).build()).getArchiveClient();
+
+ client.resizeArchive("username1", 5);
+ }
+
+ public void testChangeArchivePasswordWhenResponseIs2xx() throws Exception {
+ ArchiveClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST")
+ .endpoint(URI.create("https://api.glesys.com/archive/changepassword/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder().put(
+ "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("username", "username")
+ .put("password", "newpass").build())).build(),
+ HttpResponse.builder().statusCode(200).build()).getArchiveClient();
+
+ client.changeArchivePassword("username", "newpass");
+ }
+
+ @Test(expectedExceptions = {ResourceNotFoundException.class})
+ public void testChangeArchivePasswordWhenResponseIs4xxThrows() throws Exception {
+ ArchiveClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST")
+ .endpoint(URI.create("https://api.glesys.com/archive/changepassword/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder().put(
+ "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("username", "username")
+ .put("password", "newpass").build())).build(),
+ HttpResponse.builder().statusCode(404).build()).getArchiveClient();
+
+ client.changeArchivePassword("username", "newpass");
+ }
+
+ public void testGetArchiveAllowedArgumentsWhenResponseIs2xx() throws Exception {
+ ArchiveClient client = requestSendsResponse(
+ HttpRequest.builder().method("GET")
+ .endpoint(URI.create("https://api.glesys.com/archive/allowedarguments/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+ .build()).build(),
+ HttpResponse.builder().statusCode(200).payload(payloadFromResource("/archive_allowed_arguments.json")).build()).getArchiveClient();
+ ArchiveAllowedArguments expected = ArchiveAllowedArguments.builder().archiveSizes(10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 125, 150, 175, 200, 225, 250, 275, 300, 325, 350, 375, 400, 425, 450, 475, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000).build();
+
+ assertEquals(client.getArchiveAllowedArguments(), expected);
+ }
+
+ public void testGetArchiveAllowedArguments4xxWhenResponseIs2xx() throws Exception {
+ ArchiveClient client = requestSendsResponse(
+ HttpRequest.builder().method("GET")
+ .endpoint(URI.create("https://api.glesys.com/archive/allowedarguments/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()).build(),
+ HttpResponse.builder().statusCode(404).build()).getArchiveClient();
+
+ assertNull(client.getArchiveAllowedArguments());
+ }
+}
diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/BaseGleSYSAsyncClientTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/BaseGleSYSAsyncClientTest.java
index 26e799a..e52ef60 100644
--- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/BaseGleSYSAsyncClientTest.java
+++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/BaseGleSYSAsyncClientTest.java
@@ -45,11 +45,8 @@
/**
* @author Adrian Cole
- * @author Adam Lowe
*/
public abstract class BaseGleSYSAsyncClientTest<T> extends RestClientTest<T> {
- protected Class<T> asyncClientClass;
- protected String remoteServicePrefix;
@Override
protected void checkFilters(HttpRequest request) {
@@ -62,83 +59,4 @@
Properties props = new Properties();
return new RestContextFactory().createContextSpec("glesys", "username", "apiKey", props);
}
-
- @Deprecated
- protected Map.Entry<String, String> newEntry(String key, Object value) {
- return Maps.immutableEntry(key, value.toString());
- }
-
- /**
- * Test that a method call is annotated correctly.
- * <p/>
- * @param localMethod the method to call in asyncClientClass
- * @param remoteCall the name of the expected call on the remote server
- * @param httpMethod "GET" or "POST"
- * @param expectResponse if true check Accept header and response parsers
- * @param exceptionParser the class of exception handler expected
- * @param args either Map.Entry or BaseHttpRequestOptions that make up the arguments to the method
- */
- //TODO: kill this and related logic and transition to BaseRestClientExpectTest<GleSYSClient>
- @Deprecated
- protected void testMethod(String localMethod, String remoteCall, String httpMethod, boolean expectResponse,
- Class<?> exceptionParser, Object... args) throws Exception {
- testMethod(localMethod, remoteCall, httpMethod, expectResponse, ParseFirstJsonValueNamed.class, exceptionParser,
- args);
- }
-
- @Deprecated
- @SuppressWarnings("unchecked")
- protected void testMethod(String localMethod, String remoteCall, String httpMethod, boolean expectResponse, Class<?> responseParser, Class<?> exceptionParser, Object... args) throws Exception {
- List<String> argStrings = new ArrayList<String>();
- List<Object> argValues = new ArrayList<Object>();
-
- for (Object arg : args) {
- if (arg instanceof BaseHttpRequestOptions) {
- for (Map.Entry<String, String> httpEntry : ((BaseHttpRequestOptions) arg).buildFormParameters().entries()) {
- argStrings.add(httpEntry.getKey() + "=" + httpEntry.getValue());
- }
- argValues.add(arg);
- } else {
- Map.Entry<String, String> entry = (Map.Entry<String, String>) arg;
- argStrings.add(entry.getKey() + "=" + Strings2.urlEncode(entry.getValue()));
- argValues.add(entry.getValue());
- }
- }
-
- Method method = null;
- for (Method m : asyncClientClass.getMethods()) {
- if (m.getName().equals(localMethod)) {
- assertNull(method, "More than one method called " + localMethod + " in class " + asyncClientClass);
- method = m;
- }
- }
-
- assertNotNull(method, "Failed to locate method " + localMethod + " in class " + asyncClientClass);
-
- HttpRequest httpRequest = processor.createRequest(method, argValues.toArray());
-
- assertRequestLineEquals(httpRequest, httpMethod + " https://api.glesys.com/" + remoteServicePrefix + "/" + remoteCall + "/format/json HTTP/1.1");
-
- if (expectResponse) {
- assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
- assertResponseParserClassEquals(method, httpRequest, responseParser);
- }
-
- if (argStrings.isEmpty()) {
- assertPayloadEquals(httpRequest, null, null, false);
- } else {
- assertNotNull(httpRequest.getPayload());
- String payload = (String) httpRequest.getPayload().getRawContent();
- Iterable<String> in = Splitter.on("&").split(payload);
- assertContentHeadersEqual(httpRequest, "application/x-www-form-urlencoded", null, null, null, 0L + payload.length(), null);
- assertEquals(ImmutableSortedSet.copyOf(in), ImmutableSortedSet.copyOf(argStrings));
-
- }
-
- assertSaxResponseParserClassEquals(method, null);
- assertExceptionParserClassEquals(method, exceptionParser);
-
- checkFilters(httpRequest);
- }
-
}
diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainAsyncClientTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainAsyncClientTest.java
deleted file mode 100644
index e945854..0000000
--- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainAsyncClientTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- * 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.glesys.features;
-
-import java.util.Map;
-
-import org.jclouds.glesys.options.DomainOptions;
-import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
-import org.jclouds.rest.internal.RestAnnotationProcessor;
-import org.testng.annotations.Test;
-
-import com.google.inject.TypeLiteral;
-
-/**
- * Tests annotation parsing of {@code DomainAsyncClient}
- *
- * @author Adam Lowe
- */
-@Test(groups = "unit", testName = "DomainAsyncClientTest")
-public class DomainAsyncClientTest extends BaseGleSYSAsyncClientTest<DomainAsyncClient> {
- public DomainAsyncClientTest() {
- asyncClientClass = DomainAsyncClient.class;
- remoteServicePrefix = "domain";
- }
-
- private Map.Entry<String, String> domainName = newEntry("domain", "cl666666someuser");
-
- public void testListDomains() throws Exception {
- testMethod("listDomains", "list", "POST", true, ReturnEmptySetOnNotFoundOr404.class);
- }
-
- public void testAddDomain() throws Exception {
- testMethod("addDomain", "add", "POST", false, MapHttp4xxCodesToExceptions.class, newEntry("name", "cl66666_x"),
- DomainOptions.Builder.primaryNameServer("ns1.somewhere.x").expire("1").minimum("1").refresh("1").
- responsiblePerson("Tester").retry("1").ttl(1));
- testMethod("addDomain", "add", "POST", false, MapHttp4xxCodesToExceptions.class, newEntry("name", "cl66666_x"));
- }
-
- public void testEditDomain() throws Exception {
- testMethod("editDomain", "edit", "POST", false, MapHttp4xxCodesToExceptions.class, newEntry("domain", "x"));
- }
-
- public void testDeleteDomain() throws Exception {
- testMethod("deleteDomain", "delete", "POST", false, MapHttp4xxCodesToExceptions.class, domainName);
- }
-
- @Override
- protected TypeLiteral<RestAnnotationProcessor<DomainAsyncClient>> createTypeLiteral() {
- return new TypeLiteral<RestAnnotationProcessor<DomainAsyncClient>>() {
- };
- }
-}
diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainClientExpectTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainClientExpectTest.java
new file mode 100644
index 0000000..b51208b
--- /dev/null
+++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainClientExpectTest.java
@@ -0,0 +1,164 @@
+/**
+ * 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.glesys.features;
+
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.glesys.GleSYSClient;
+import org.jclouds.glesys.domain.Domain;
+import org.jclouds.glesys.options.DomainAddOptions;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.rest.BaseRestClientExpectTest;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.testng.annotations.Test;
+
+import java.net.URI;
+import java.text.SimpleDateFormat;
+import java.util.Set;
+
+import static org.jclouds.io.Payloads.newUrlEncodedFormPayload;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Tests annotation parsing of {@code DomainAsyncClient}
+ *
+ * @author Adam Lowe
+ */
+@Test(groups = "unit", testName = "DomainClientExpectTest")
+public class DomainClientExpectTest extends BaseRestClientExpectTest<GleSYSClient> {
+ public DomainClientExpectTest() {
+ provider = "glesys";
+ }
+
+ public void testListDomainsWhenResponseIs2xx() throws Exception {
+ //DomainClient client = createMock("list", "POST", 200, "/domain_list.json");
+
+ DomainClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/domain/list/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .build(),
+ HttpResponse.builder().statusCode(200).payload(payloadFromResource("/domain_list.json")).build()).getDomainClient();
+
+ Set<Domain> expected = ImmutableSet.<Domain>of(
+ Domain.builder().domain("adamlowe.net").createTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2011-12-20 10:58:51")).build());
+
+ assertEquals(client.listDomains(), expected);
+ }
+
+ public void testListDomainsWhenResponseIs4xxReturnsEmpty() throws Exception {
+ DomainClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/domain/list/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .build(),
+ HttpResponse.builder().statusCode(404).build()).getDomainClient();
+
+ assertTrue(client.listDomains().isEmpty());
+ }
+
+ public void testAddDomainWhenResponseIs2xx() throws Exception {
+ DomainClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/domain/add/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder().put(
+ "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("name", "cl66666_x").build())).build(),
+ HttpResponse.builder().statusCode(200).build()).getDomainClient();
+
+ client.addDomain("cl66666_x");
+ }
+
+
+ public void testAddDomainWithOptsWhenResponseIs2xx() throws Exception {
+ DomainClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/domain/add/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder().put(
+ "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("name", "cl66666_x")
+ .put("primary_ns", "ns1.somewhere.x")
+ .put("expire", "1")
+ .put("minimum", "1")
+ .put("refresh", "1")
+ .put("resp_person", "Tester.")
+ .put("retry", "1")
+ .put("ttl", "1")
+ .build())).build(),
+ HttpResponse.builder().statusCode(200).build()).getDomainClient();
+ DomainAddOptions options = (DomainAddOptions) DomainAddOptions.Builder.primaryNameServer("ns1.somewhere.x")
+ .expire(1).minimum(1).refresh(1).responsiblePerson("Tester").retry(1).ttl(1);
+
+ client.addDomain("cl66666_x", options);
+ }
+
+ public void testEditDomainWhenResponseIs2xx() throws Exception {
+ DomainClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/domain/edit/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder().put(
+ "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("domain", "x").build())).build(),
+ HttpResponse.builder().statusCode(200).build()).getDomainClient();
+
+ client.editDomain("x");
+ }
+
+ @Test(expectedExceptions = {ResourceNotFoundException.class})
+ public void testEditDomainWhenResponseIs4xxThrows() throws Exception {
+ DomainClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/domain/edit/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder().put(
+ "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("domain", "x").build())).build(),
+ HttpResponse.builder().statusCode(404).build()).getDomainClient();
+
+ client.editDomain("x");
+ }
+
+ public void testDeleteDomainWhenResponseIs2xx() throws Exception {
+ DomainClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/domain/delete/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder().put(
+ "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("domain", "x").build())).build(),
+ HttpResponse.builder().statusCode(200).build()).getDomainClient();
+
+ client.deleteDomain("x");
+ }
+
+ @Test(expectedExceptions = {ResourceNotFoundException.class})
+ public void testDeleteDomainWhenResponseIs4xxThrows() throws Exception {
+ DomainClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/domain/delete/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder().put(
+ "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("domain", "x").build())).build(),
+ HttpResponse.builder().statusCode(404).build()).getDomainClient();
+
+ client.deleteDomain("x");
+ }
+}
diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainClientLiveTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainClientLiveTest.java
index 4ab2e64..37abc25 100644
--- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainClientLiveTest.java
+++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainClientLiveTest.java
@@ -18,12 +18,17 @@
*/
package org.jclouds.glesys.features;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import java.util.Set;
import java.util.concurrent.TimeUnit;
+import org.jclouds.glesys.domain.Domain;
import org.jclouds.glesys.domain.DomainRecord;
+import org.jclouds.glesys.options.DomainOptions;
+import org.jclouds.glesys.options.DomainRecordEditOptions;
import org.jclouds.predicates.RetryablePredicate;
import org.testng.annotations.AfterGroups;
import org.testng.annotations.BeforeGroups;
@@ -80,12 +85,58 @@
private RetryablePredicate<Integer> recordCounter;
@Test
+ public void testEditDomain() throws Exception {
+ client.editDomain(testDomain, DomainOptions.Builder.responsiblePerson("tester.jclouds.org"));
+ assertTrue(client.listDomains().contains(Domain.builder().domain(testDomain).build()));
+ }
+
+ @Test
public void testCreateRecord() throws Exception {
int before = client.listRecords(testDomain).size();
client.addRecord(testDomain, "test", "A", "127.0.0.1");
assertTrue(recordCounter.apply(before + 1));
+
+ for(DomainRecord record : client.listRecords(testDomain)) {
+ if ("test".equals(record.getHost())) {
+ assertEquals(record.getType(), "A");
+ assertEquals(record.getData(), "127.0.0.1");
+ }
+ }
+ }
+
+ @Test
+ public void testEditRecord() throws Exception {
+ int before = client.listRecords(testDomain).size();
+
+ client.addRecord(testDomain, "testeditbefore", "A", "127.0.0.1");
+
+ assertTrue(recordCounter.apply(before + 1));
+
+ String recordId = null;
+ for(DomainRecord record : client.listRecords(testDomain)) {
+ if ("testeditbefore".equals(record.getHost())) {
+ assertEquals(record.getType(), "A");
+ assertEquals(record.getData(), "127.0.0.1");
+ recordId = record.getId();
+ }
+ }
+
+ assertNotNull(recordId);
+
+ client.editRecord(recordId, DomainRecordEditOptions.Builder.host("testeditafter"));
+
+ boolean found = false;
+ for(DomainRecord record : client.listRecords(testDomain)) {
+ if (recordId.equals(record.getId())) {
+ assertEquals(record.getHost(), "testeditafter");
+ assertEquals(record.getType(), "A");
+ assertEquals(record.getData(), "127.0.0.1");
+ found = true;
+ }
+ }
+ assertTrue(found);
}
@Test
diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailAsyncClientTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailAsyncClientTest.java
deleted file mode 100644
index 84fb0ca..0000000
--- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailAsyncClientTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * 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.glesys.features;
-
-import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
-import org.jclouds.rest.internal.RestAnnotationProcessor;
-import org.testng.annotations.Test;
-
-import com.google.inject.TypeLiteral;
-
-/**
- * Tests annotation parsing of {@code ArchiveAsyncClient}
- *
- * @author Adam Lowe
- */
-@Test(groups = "unit", testName = "EmailAsyncClientTest")
-public class EmailAsyncClientTest extends BaseGleSYSAsyncClientTest<EmailAsyncClient> {
- public EmailAsyncClientTest() {
- asyncClientClass = EmailAsyncClient.class;
- remoteServicePrefix = "email";
- }
-
- public void testList() throws Exception {
- testMethod("listAccounts", "list", "POST", true, ReturnEmptySetOnNotFoundOr404.class, newEntry("domain","test"));
- }
-
- public void testOverview() throws Exception {
- testMethod("getEmailOverview", "overview", "POST", true, ReturnEmptySetOnNotFoundOr404.class);
- }
-
- public void testCreateAccount() throws Exception {
- testMethod("createAccount", "createaccount", "POST", false, MapHttp4xxCodesToExceptions.class,
- newEntry("emailaccount", "jclouds.org"), newEntry("password", "test@jclouds.org"));
- }
-
- public void testCreateAlias() throws Exception {
- testMethod("createAlias", "createalias", "POST", false, MapHttp4xxCodesToExceptions.class,
- newEntry("emailalias", "test2@jclouds.org"), newEntry("goto", "test@jclouds.org"));
- }
-
- public void testEditAlias() throws Exception {
- testMethod("editAlias", "editalias", "POST", false, MapHttp4xxCodesToExceptions.class,
- newEntry("emailalias", "test2@jclouds.org"), newEntry("goto", "test1@jclouds.org"));
- }
-
- @Override
- protected TypeLiteral<RestAnnotationProcessor<EmailAsyncClient>> createTypeLiteral() {
- return new TypeLiteral<RestAnnotationProcessor<EmailAsyncClient>>() {
- };
- }
-}
diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientExpectTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientExpectTest.java
new file mode 100644
index 0000000..ac95aae
--- /dev/null
+++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientExpectTest.java
@@ -0,0 +1,211 @@
+/**
+ * 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.glesys.features;
+
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.glesys.GleSYSClient;
+import org.jclouds.glesys.domain.Email;
+import org.jclouds.glesys.domain.EmailOverview;
+import org.jclouds.glesys.domain.EmailOverviewDomain;
+import org.jclouds.glesys.domain.EmailOverviewSummary;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+import org.jclouds.rest.AuthorizationException;
+import org.jclouds.rest.BaseRestClientExpectTest;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.testng.annotations.Test;
+
+import java.net.URI;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Set;
+
+import static org.jclouds.io.Payloads.newUrlEncodedFormPayload;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Tests annotation parsing of {@code EmailClient}
+ *
+ * @author Adam Lowe
+ */
+@Test(groups = "unit", testName = "EmailAsyncClientTest")
+public class EmailClientExpectTest extends BaseRestClientExpectTest<GleSYSClient> {
+ public EmailClientExpectTest() {
+ provider = "glesys";
+ }
+
+ public void testListWhenResponseIs2xx() throws Exception {
+ EmailClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/email/list/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(
+ ImmutableMultimap.<String, String>builder().put("domain", "test").build())).build(),
+ HttpResponse.builder().statusCode(200).payload(payloadFromResource("/email_list.json")).build()).getEmailClient();
+
+ DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+ Email.Builder builder = Email.builder().quota("200 MB").usedQuota("0 MB").antispamLevel(3).antiVirus(true).autoRespond(false).autoRespondSaveEmail(true).autoRespondMessage("false");
+ Set<Email> expected =
+ ImmutableSet.of(
+ builder.account("test@adamlowe.net").created(dateFormat.parse("2011-12-22T12:13:14")).modified(dateFormat.parse("2011-12-22T12:13:35")).build(),
+ builder.account("test2@adamlowe.net").created(dateFormat.parse("2011-12-22T12:14:29")).modified(dateFormat.parse("2011-12-22T12:14:31")).build()
+ );
+
+ assertEquals(client.listAccounts("test"), expected);
+ }
+
+ public void testListWhenResponseIs404IsEmpty() throws Exception {
+ EmailClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/email/list/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(
+ ImmutableMultimap.<String, String>builder().put("domain", "test").build())).build(),
+ HttpResponse.builder().statusCode(404).build()).getEmailClient();
+
+ assertTrue(client.listAccounts("test").isEmpty());
+ }
+
+ public void testOverviewWhenResponseIs2xx() throws Exception {
+ EmailClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/email/overview/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .build(),
+ HttpResponse.builder().statusCode(200).payload(payloadFromResource("/email_overview.json")).build()).getEmailClient();
+
+ EmailOverviewSummary summary = EmailOverviewSummary.builder().accounts(2).maxAccounts(50).aliases(0).maxAliases(1000).build();
+ EmailOverviewDomain domain = EmailOverviewDomain.builder().domain("adamlowe.net").accounts(2).aliases(0).build();
+ EmailOverview expected = EmailOverview.builder().summary(summary).domains(domain).build();
+
+ assertEquals(client.getEmailOverview(), expected);
+ }
+
+ public void testOverviewWhenResponseIs404ReturnsNull() throws Exception {
+ EmailClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/email/overview/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .build(),
+ HttpResponse.builder().statusCode(404).build()).getEmailClient();
+
+ assertNull(client.getEmailOverview());
+ }
+
+ public void testCreateAccountWhenResponseIs2xx() throws Exception {
+ EmailClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/email/createaccount/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("emailaccount", "test@jclouds.org")
+ .put("password", "newpass")
+ .build()))
+ .build(),
+ HttpResponse.builder().statusCode(200).build()).getEmailClient();
+
+ client.createAccount("test@jclouds.org", "newpass");
+ }
+
+ @Test(expectedExceptions = {ResourceNotFoundException.class})
+ public void testCreateAccountWhenResponseIs4xxThrows() throws Exception {
+ EmailClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/email/createaccount/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("emailaccount", "test@jclouds.org")
+ .put("password", "newpass")
+ .build()))
+ .build(),
+ HttpResponse.builder().statusCode(404).build()).getEmailClient();
+
+ client.createAccount("test@jclouds.org", "newpass");
+ }
+
+ public void testCreateAliasWhenResponseIs2xx() throws Exception {
+ EmailClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/email/createalias/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("emailalias", "test2@jclouds.org")
+ .put("goto", "test@jclouds.org")
+ .build()))
+ .build(),
+ HttpResponse.builder().statusCode(200).build()).getEmailClient();
+
+ client.createAlias("test2@jclouds.org", "test@jclouds.org");
+ }
+
+ @Test(expectedExceptions = {AuthorizationException.class})
+ public void testCreateAliasWhenResponseIs4xxThrows() throws Exception {
+ EmailClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/email/createalias/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("emailalias", "test2@jclouds.org")
+ .put("goto", "test@jclouds.org")
+ .build()))
+ .build(),
+ HttpResponse.builder().statusCode(401).build()).getEmailClient();
+
+ client.createAlias("test2@jclouds.org", "test@jclouds.org");
+ }
+
+ public void testEditAliasWhenResponseIs2xx() throws Exception {
+ EmailClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/email/editalias/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("emailalias", "test2@jclouds.org")
+ .put("goto", "test@jclouds.org")
+ .build()))
+ .build(),
+ HttpResponse.builder().statusCode(200).build()).getEmailClient();
+
+ client.editAlias("test2@jclouds.org", "test@jclouds.org");
+ }
+
+ @Test(expectedExceptions = {ResourceNotFoundException.class})
+ public void testEditAliasWhenResponseIs4xxThrows() throws Exception {
+ EmailClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/email/editalias/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("emailalias", "test2@jclouds.org")
+ .put("goto", "test@jclouds.org")
+ .build()))
+ .build(),
+ HttpResponse.builder().statusCode(404).build()).getEmailClient();
+
+ client.editAlias("test2@jclouds.org", "test@jclouds.org");
+ }
+}
diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientLiveTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientLiveTest.java
index 845d173..108c608 100644
--- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientLiveTest.java
+++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientLiveTest.java
@@ -16,24 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
-/**
-* 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.glesys.features;
import com.google.common.base.Predicate;
@@ -52,10 +34,10 @@
import static org.testng.Assert.*;
/**
-* Tests behavior of {@code EmailClient}
-*
-* @author Adam Lowe
-*/
+ * Tests behavior of {@code EmailClient}
+ *
+ * @author Adam Lowe
+ */
@Test(groups = "live", testName = "EmailClientLiveTest", singleThreaded = true)
public class EmailClientLiveTest extends BaseGleSYSClientLiveTest {
@@ -64,15 +46,8 @@
super.setupClient();
client = context.getApi().getEmailClient();
- try {
- client.delete("test@" + testDomain);
- client.delete("test2@" + testDomain);
- context.getApi().getDomainClient().deleteDomain(testDomain);
- } catch(Exception e) {
- }
-
serverId = createServer("test-email-jclouds").getServerId();
-
+
createDomain(testDomain);
emailAccountCounter = new RetryablePredicate<Integer>(
@@ -80,42 +55,55 @@
public boolean apply(Integer value) {
return client.listAccounts(testDomain).size() == value;
}
- }, 30, 1, TimeUnit.SECONDS);
-
+ }, 90, 5, TimeUnit.SECONDS);
+
+ assertTrue(emailAccountCounter.apply(0));
}
-
@AfterGroups(groups = {"live"})
public void tearDown() {
client.delete("test@" + testDomain);
+ client.delete("test1@" + testDomain);
assertTrue(emailAccountCounter.apply(0));
context.getApi().getDomainClient().deleteDomain(testDomain);
context.getApi().getServerClient().destroyServer(serverId, ServerDestroyOptions.Builder.discardIp());
super.tearDown();
}
-
+
private EmailClient client;
private String serverId;
private final String testDomain = "email-test.jclouds.org";
private RetryablePredicate<Integer> emailAccountCounter;
-
+
@Test
- public void createEmail() {
- client.createAccount("test@" + testDomain, "password", EmailCreateOptions.Builder.antiVirus(true));
+ public void testCreateEmail() {
+ client.createAccount("test@" + testDomain, "password",
+ EmailCreateOptions.Builder.antiVirus(true).autorespond(true).autorespondMessage("out of office"));
+
assertTrue(emailAccountCounter.apply(1));
+
+ client.createAccount("test1@" + testDomain, "password");
+
+ assertTrue(emailAccountCounter.apply(2));
}
- @Test(dependsOnMethods = "createEmail")
- public void createAlias() {
+ @Test(dependsOnMethods = "testCreateEmail")
+ public void testAliases() {
client.createAlias("test2@" + testDomain, "test@" + testDomain);
EmailOverview overview = client.getEmailOverview();
assertTrue(overview.getSummary().getAliases() == 1);
+
+ // TODO verify the result of editing the alias
+ client.editAlias("test2@" + testDomain, "test1@" + testDomain);
+ overview = client.getEmailOverview();
+ assertTrue(overview.getSummary().getAliases() == 1);
+
client.delete("test2@" + testDomain);
overview = client.getEmailOverview();
assertTrue(overview.getSummary().getAliases() == 0);
}
-
- @Test(dependsOnMethods = "createEmail")
+
+ @Test(dependsOnMethods = "testCreateEmail")
public void testOverview() throws Exception {
EmailOverview overview = client.getEmailOverview();
assertNotNull(overview.getSummary());
@@ -125,30 +113,30 @@
assertTrue(overview.getSummary().getMaxAliases() > 0);
assertNotNull(overview.getDomains());
assertFalse(overview.getDomains().isEmpty());
-
+
EmailOverviewDomain domain = EmailOverviewDomain.builder().domain(testDomain).accounts(1).build();
assertTrue(overview.getDomains().contains(domain));
}
- @Test(dependsOnMethods = "createEmail")
+ @Test(dependsOnMethods = "testCreateEmail")
public void testListAccounts() throws Exception {
Set<Email> accounts = client.listAccounts(testDomain);
assertTrue(accounts.size() >= 1);
}
- @Test(dependsOnMethods = "createEmail")
+ @Test(dependsOnMethods = "testCreateEmail")
public void testEditAccount() throws Exception {
Set<Email> accounts = client.listAccounts(testDomain);
- for(Email account : accounts) {
+ for (Email account : accounts) {
if (account.getAccount().equals("test@" + testDomain)) {
assertTrue(account.getAntiVirus());
}
}
-
+
client.editAccount("test@" + testDomain, EmailEditOptions.Builder.antiVirus(false));
-
+
accounts = client.listAccounts(testDomain);
- for(Email account : accounts) {
+ for (Email account : accounts) {
if (account.getAccount().equals("test@" + testDomain)) {
assertFalse(account.getAntiVirus());
}
diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerAsyncClientTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerAsyncClientTest.java
deleted file mode 100644
index 283c622..0000000
--- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerAsyncClientTest.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/**
- * 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.glesys.features;
-
-import java.util.Map;
-
-import org.jclouds.glesys.functions.ParseServerTemplatesFromHttpResponse;
-import org.jclouds.glesys.options.ServerCloneOptions;
-import org.jclouds.glesys.options.ServerCreateOptions;
-import org.jclouds.glesys.options.ServerDestroyOptions;
-import org.jclouds.glesys.options.ServerEditOptions;
-import org.jclouds.glesys.options.ServerStatusOptions;
-import org.jclouds.glesys.options.ServerStopOptions;
-import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
-import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
-import org.jclouds.rest.internal.RestAnnotationProcessor;
-import org.testng.annotations.Test;
-
-import com.google.inject.TypeLiteral;
-
-/**
- * Tests annotation parsing of {@code ServerAsyncClient}
- *
- * @author Adrian Cole
- * @author Adam Lowe
- */
-@Test(groups = "unit", testName = "ServerAsyncClientTest")
-public class ServerAsyncClientTest extends BaseGleSYSAsyncClientTest<ServerAsyncClient> {
-
- public ServerAsyncClientTest() {
- asyncClientClass = ServerAsyncClient.class;
- remoteServicePrefix = "server";
- }
-
- private Map.Entry<String, String> serverIdOnly = newEntry("serverid", "abcd");
-
- public void testListServers() throws Exception {
- testMethod("listServers", "list", "POST", true, ReturnEmptySetOnNotFoundOr404.class);
- }
-
- public void testGetAllowedArguments() throws Exception {
- testMethod("getServerAllowedArguments", "allowedarguments", "GET", true, MapHttp4xxCodesToExceptions.class);
- }
-
- public void testGetTemplates() throws Exception {
- testMethod("getTemplates", "templates", "GET", true, ParseServerTemplatesFromHttpResponse.class,
- MapHttp4xxCodesToExceptions.class);
- }
-
- public void testGetServer() throws Exception {
- testMethod("getServerDetails", "details", "POST", true, ReturnNullOnNotFoundOr404.class, serverIdOnly);
- }
-
- @Test
- public void testCreateServer() throws Exception {
- testMethod("createServer", "create", "POST", true, MapHttp4xxCodesToExceptions.class,
- newEntry("datacenter", "Falkenberg"), newEntry("platform", "OpenVZ"),
- newEntry("hostname", "jclouds-test"), newEntry("template", "Ubuntu%2032-bit"),
- newEntry("disksize", 5), newEntry("memorysize", 512), newEntry("cpucores", 1),
- newEntry("rootpw", "password"), newEntry("transfer", 50));
- testMethod("createServer", "create", "POST", true, MapHttp4xxCodesToExceptions.class,
- newEntry("datacenter", "Falkenberg"), newEntry("platform", "OpenVZ"),
- newEntry("hostname", "jclouds-test"), newEntry("template", "Ubuntu%2032-bit"),
- newEntry("disksize", 5), newEntry("memorysize", 512), newEntry("cpucores", 1),
- newEntry("rootpw", "password"), newEntry("transfer", 50),
- ServerCreateOptions.Builder.description("Description-of-server").ip("10.0.0.1"));
- }
-
- @Test
- public void testEditServer() throws Exception {
- testMethod("editServer", "edit", "POST", false, MapHttp4xxCodesToExceptions.class, serverIdOnly);
- testMethod("editServer", "edit", "POST", false, MapHttp4xxCodesToExceptions.class, serverIdOnly,
- ServerEditOptions.Builder.description("Description-of-server").disksize(1).memorysize(512).cpucores(1).hostname("jclouds-test"));
- }
-
- @Test
- public void testCloneServer() throws Exception {
- testMethod("cloneServer", "clone", "POST", false, MapHttp4xxCodesToExceptions.class, serverIdOnly, newEntry("hostname", "somename"));
- testMethod("cloneServer", "clone", "POST", false, MapHttp4xxCodesToExceptions.class, serverIdOnly, newEntry("hostname", "somename"),
- ServerCloneOptions.Builder.description("Description-of-server").disksize(1).memorysize(512).cpucores(1).hostname("jclouds-test"));
- }
-
- public void testGetServerStatus() throws Exception {
- testMethod("getServerStatus", "status", "POST", true, ReturnNullOnNotFoundOr404.class, serverIdOnly);
- testMethod("getServerStatus", "status", "POST", true, ReturnNullOnNotFoundOr404.class, serverIdOnly, ServerStatusOptions.Builder.state());
- }
-
- public void testGetServerLimits() throws Exception {
- testMethod("getServerLimits", "limits", "POST", true, ReturnNullOnNotFoundOr404.class, serverIdOnly);
- }
-
- public void testGetServerConsole() throws Exception {
- testMethod("getServerConsole", "console", "POST", true, ReturnNullOnNotFoundOr404.class, serverIdOnly);
- }
-
- public void testStartServer() throws Exception {
- testMethod("startServer", "start", "POST", false, MapHttp4xxCodesToExceptions.class, serverIdOnly);
- }
-
- public void testStopServer() throws Exception {
- testMethod("stopServer", "stop", "POST", false, MapHttp4xxCodesToExceptions.class, serverIdOnly);
- testMethod("stopServer", "stop", "POST", false, MapHttp4xxCodesToExceptions.class, serverIdOnly, ServerStopOptions.Builder.hard());
- }
-
- public void testRebootServer() throws Exception {
- testMethod("rebootServer", "reboot", "POST", false, MapHttp4xxCodesToExceptions.class, serverIdOnly);
- }
-
- public void testDestroyServer() throws Exception {
- testMethod("destroyServer", "destroy", "POST", false, MapHttp4xxCodesToExceptions.class, serverIdOnly, ServerDestroyOptions.Builder.keepIp());
- testMethod("destroyServer", "destroy", "POST", false, MapHttp4xxCodesToExceptions.class, serverIdOnly, ServerDestroyOptions.Builder.discardIp());
- }
-
- @Override
- protected TypeLiteral<RestAnnotationProcessor<ServerAsyncClient>> createTypeLiteral() {
- return new TypeLiteral<RestAnnotationProcessor<ServerAsyncClient>>() {
- };
- }
-}
diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientExpectTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientExpectTest.java
new file mode 100644
index 0000000..4826b52
--- /dev/null
+++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientExpectTest.java
@@ -0,0 +1,452 @@
+/**
+ * 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.glesys.features;
+
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.glesys.GleSYSClient;
+import org.jclouds.glesys.domain.Server;
+import org.jclouds.glesys.domain.ServerCreated;
+import org.jclouds.glesys.domain.ServerCreatedIp;
+import org.jclouds.glesys.domain.ServerDetails;
+import org.jclouds.glesys.options.*;
+import org.jclouds.glesys.parse.*;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.rest.AuthorizationException;
+import org.jclouds.rest.BaseRestClientExpectTest;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.testng.annotations.Test;
+
+import java.net.URI;
+
+import static org.jclouds.io.Payloads.newUrlEncodedFormPayload;
+import static org.testng.Assert.*;
+
+/**
+ * Tests annotation parsing of {@code ServerAsyncClient}
+ *
+ * @author Adrian Cole
+ * @author Adam Lowe
+ */
+@Test(groups = "unit", testName = "ServerAsyncClientTest")
+public class ServerClientExpectTest extends BaseRestClientExpectTest<GleSYSClient> {
+
+ public ServerClientExpectTest() {
+ provider = "glesys";
+ }
+
+ public void testListServersWhenResponseIs2xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/list/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()).build(),
+ HttpResponse.builder().statusCode(204).payload(payloadFromResource("/server_list.json")).build()).getServerClient();
+ Server expected = Server.builder().id("vz1541880").hostname("mammamia").datacenter("Falkenberg").platform("OpenVZ").build();
+
+ assertEquals(client.listServers(), ImmutableSet.<Server>of(expected));
+ }
+
+ public void testListServersWhenReponseIs404IsEmpty() {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/list/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()).build(),
+ HttpResponse.builder().statusCode(404).build()).getServerClient();
+
+ assertTrue(client.listServers().isEmpty());
+ }
+
+ public void testGetAllowedArgumentsWhenResponseIs2xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("GET").endpoint(URI.create("https://api.glesys.com/server/allowedarguments/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()).build(),
+ HttpResponse.builder().statusCode(204).payload(payloadFromResource("/server_allowed_arguments.json")).build()).getServerClient();
+
+ assertEquals(client.getServerAllowedArguments(), new ParseServerAllowedArgumentsTest().expected());
+ }
+
+ public void testGetTemplatesWhenResponseIs2xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("GET").endpoint(URI.create("https://api.glesys.com/server/templates/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()).build(),
+ HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_templates.json")).build()).getServerClient();
+
+ assertEquals(client.getTemplates(), new ParseServerTemplatesTest().expected());
+ }
+
+ public void testGetServerWhenResponseIs2xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/details/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("serverid", "server1ssg-1.1").build())).build(),
+ HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_details.json")).build()).getServerClient();
+
+ ServerDetails actual = client.getServerDetails("server1ssg-1.1");
+ assertEquals(actual.toString(), new ParseServerDetailsTest().expected().toString());
+ }
+
+ @Test
+ public void testCreateServerWhenResponseIs2xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/create/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("cpucores", "1").put("memorysize", "512")
+ .put("datacenter", "Falkenberg")
+ .put("transfer", "50")
+ .put("rootpw", "password")
+ .put("hostname", "jclouds-test")
+ .put("platform", "OpenVZ")
+ .put("template", "Ubuntu 32-bit")
+ .put("disksize", "5").build())).build(),
+ HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_created.json")).build()).getServerClient();
+ ServerCreated expected = ServerCreated.builder().hostname("jclouds-test").id("xm3630641").ips(ServerCreatedIp.builder().ip("109.74.10.27").build()).build();
+
+ assertEquals(client.createServer("Falkenberg", "OpenVZ", "jclouds-test", "Ubuntu 32-bit", 5, 512, 1, "password", 50), expected);
+ }
+
+ public void testCreateServerWithOptsWhenResponseIs2xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/create/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("cpucores", "1").put("memorysize", "512")
+ .put("datacenter", "Falkenberg")
+ .put("transfer", "50")
+ .put("rootpw", "password")
+ .put("hostname", "jclouds-test")
+ .put("platform", "OpenVZ")
+ .put("template", "Ubuntu 32-bit")
+ .put("disksize", "5")
+ .put("description", "Description-of-server")
+ .put("ip", "10.0.0.1").build())).build(),
+ HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_created.json")).build()).getServerClient();
+ ServerCreateOptions options = ServerCreateOptions.Builder.description("Description-of-server").ip("10.0.0.1");
+ ServerCreated expected = ServerCreated.builder().hostname("jclouds-test").id("xm3630641").ips(ServerCreatedIp.builder().ip("109.74.10.27").build()).build();
+
+ assertEquals(client.createServer("Falkenberg", "OpenVZ", "jclouds-test", "Ubuntu 32-bit", 5, 512, 1, "password", 50, options), expected);
+ }
+
+ @Test
+ public void testEditServerWhenResponseIs2xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/edit/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("serverid", "server111").build())).build(),
+ HttpResponse.builder().statusCode(206).build()).getServerClient();
+
+ client.editServer("server111");
+ }
+
+ @Test
+ public void testEditServerWithOptsWhenResponseIs2xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/edit/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("serverid", "server111")
+ .put("description", "Description-of-server")
+ .put("disksize", "1")
+ .put("memorysize", "512")
+ .put("cpucores", "1")
+ .put("hostname", "jclouds-test")
+ .build())).build(),
+ HttpResponse.builder().statusCode(200).build()).getServerClient();
+
+ ServerEditOptions options =
+ ServerEditOptions.Builder.description("Description-of-server").disksize(1).memorysize(512).cpucores(1).hostname("jclouds-test");
+
+ client.editServer("server111", options);
+ }
+
+ @Test
+ public void testCloneServerWhenResponseIs2xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/clone/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("serverid", "server111")
+ .put("hostname", "hostname1").build())).build(),
+ HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_created.json")).build()).getServerClient();
+ ServerCreated expected = ServerCreated.builder().hostname("jclouds-test").id("xm3630641").ips(ServerCreatedIp.builder().ip("109.74.10.27").build()).build();
+
+ assertEquals(client.cloneServer("server111", "hostname1"), expected);
+ }
+
+ @Test
+ public void testCloneServerWithOptsWhenResponseIs2xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/clone/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("serverid", "server111")
+ .put("hostname", "hostname1")
+ .put("description", "Description-of-server")
+ .put("disksize", "1")
+ .put("memorysize", "512")
+ .put("cpucores", "1").build())).build(),
+ HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_created.json")).build()).getServerClient();
+ ServerCloneOptions options = (ServerCloneOptions) ServerCloneOptions.Builder.description("Description-of-server").disksize(1).memorysize(512).cpucores(1);
+ ServerCreated expected = ServerCreated.builder().hostname("jclouds-test").id("xm3630641").ips(ServerCreatedIp.builder().ip("109.74.10.27").build()).build();
+
+ assertEquals(client.cloneServer("server111", "hostname1", options), expected);
+ }
+
+ @Test(expectedExceptions = {ResourceNotFoundException.class})
+ public void testCloneServerWhenResponseIs4xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/clone/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("serverid", "server111")
+ .put("hostname", "hostname1").build())).build(),
+ HttpResponse.builder().statusCode(404).build()).getServerClient();
+
+ client.cloneServer("server111", "hostname1");
+ }
+
+ public void testGetServerStatusWhenResponseIs2xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/status/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("serverid", "server111").build())).build(),
+ HttpResponse.builder().statusCode(206).payload(payloadFromResource("/server_status.json")).build())
+ .getServerClient();
+
+ assertEquals(client.getServerStatus("server111"), new ParseServerStatusTest().expected());
+ }
+
+ public void testGetServerStatusWithOptsWhenResponseIs2xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/status/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("serverid", "server321").put("statustype", "state").build())).build(),
+ HttpResponse.builder().statusCode(206).payload(payloadFromResource("/server_status.json")).build())
+ .getServerClient();
+
+ assertEquals(client.getServerStatus("server321", ServerStatusOptions.Builder.state()), new ParseServerStatusTest().expected());
+ }
+
+ public void testGetServerStatusWhenResponseIs4xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/status/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("serverid", "server321").put("statustype", "state").build())).build(),
+ HttpResponse.builder().statusCode(404).build())
+ .getServerClient();
+
+ assertNull(client.getServerStatus("server321", ServerStatusOptions.Builder.state()));
+ }
+
+ public void testGetServerLimitsWhenResponseIs2xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/limits/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("serverid", "server321").build())).build(),
+ HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_limits.json")).build())
+ .getServerClient();
+
+ client.getServerLimits("server321");
+ }
+
+ public void testGetServerConsoleWhenResponseIs2xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/console/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("serverid", "server322").build())).build(),
+ HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_console.json")).build())
+ .getServerClient();
+
+ assertEquals(client.getServerConsole("server322"), new ParseServerConsoleTest().expected());
+ }
+
+ public void testGetServerConsoleWhenResponseIs4xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/console/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Accept", "application/json")
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("serverid", "server322").build())).build(),
+ HttpResponse.builder().statusCode(404).build())
+ .getServerClient();
+
+ assertNull(client.getServerConsole("server322"));
+ }
+
+ public void testStartServerWhenResponseIs2xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/start/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("serverid", "server777").build())).build(),
+ HttpResponse.builder().statusCode(200).build())
+ .getServerClient();
+
+ client.startServer("server777");
+ }
+
+ @Test(expectedExceptions = {AuthorizationException.class})
+ public void testStartServerWhenResponseIs4xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/start/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("serverid", "server777").build())).build(),
+ HttpResponse.builder().statusCode(401).build())
+ .getServerClient();
+
+ client.startServer("server777");
+ }
+
+ public void testStopServerWhenResponseIs2xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/stop/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("serverid", "server777").build())).build(),
+ HttpResponse.builder().statusCode(200).build())
+ .getServerClient();
+
+ client.stopServer("server777");
+ }
+
+ public void testHardStopServerWhenResponseIs2xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/stop/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("serverid", "server777").put("type", "hard").build())).build(),
+ HttpResponse.builder().statusCode(200).build())
+ .getServerClient();
+
+ client.stopServer("server777", ServerStopOptions.Builder.hard());
+ }
+
+ @Test(expectedExceptions = {AuthorizationException.class})
+ public void testStopServerWhenResponseIs4xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/stop/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("serverid", "server777").build())).build(),
+ HttpResponse.builder().statusCode(401).build())
+ .getServerClient();
+
+ client.stopServer("server777");
+ }
+
+ public void testRebootServerWhenResponseIs2xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/reboot/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("serverid", "server777").build())).build(),
+ HttpResponse.builder().statusCode(200).build())
+ .getServerClient();
+
+ client.rebootServer("server777");
+ }
+
+ @Test(expectedExceptions = {AuthorizationException.class})
+ public void testRebootServerWhenResponseIs4xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/reboot/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("serverid", "server777").build())).build(),
+ HttpResponse.builder().statusCode(401).build())
+ .getServerClient();
+
+ client.rebootServer("server777");
+ }
+
+ public void testDestroyServerWhenResponseIs2xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/destroy/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("serverid", "server777").put("keepip", "1").build())).build(),
+ HttpResponse.builder().statusCode(200).build())
+ .getServerClient();
+
+ client.destroyServer("server777", ServerDestroyOptions.Builder.keepIp());
+ }
+
+ @Test(expectedExceptions = {AuthorizationException.class})
+ public void testDestroyServerWhenResponseIs4xx() throws Exception {
+ ServerClient client = requestSendsResponse(
+ HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/destroy/format/json"))
+ .headers(ImmutableMultimap.<String, String>builder()
+ .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build())
+ .payload(newUrlEncodedFormPayload(ImmutableMultimap.<String, String>builder()
+ .put("serverid", "server777").put("keepip", "0").build())).build(),
+ HttpResponse.builder().statusCode(401).build())
+ .getServerClient();
+
+ client.destroyServer("server777", ServerDestroyOptions.Builder.discardIp());
+ }
+
+}
diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientLiveTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientLiveTest.java
index ee0230e..6f28007 100644
--- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientLiveTest.java
+++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientLiveTest.java
@@ -98,26 +98,19 @@
@Test
public void testListTemplates() throws Exception {
- Map<String,Set<ServerTemplate>> templates = client.getTemplates();
+ Set<ServerTemplate> templates = client.getTemplates();
- assertTrue(templates.containsKey("OpenVZ"));
- assertTrue(templates.containsKey("Xen"));
-
- for(ServerTemplate template : templates.get("OpenVZ")) {
- checkTemplate(template, "OpenVZ");
- }
-
- for(ServerTemplate template : templates.get("Xen")) {
- checkTemplate(template, "Xen");
+ for(ServerTemplate template : templates) {
+ checkTemplate(template);
}
}
- private void checkTemplate(ServerTemplate t, String platform) {
+ private void checkTemplate(ServerTemplate t) {
assertNotNull(t);
assertNotNull(t.getName());
assertNotNull(t.getOs());
- assertEquals(t.getPlatform(), platform);
+ assertNotNull(t.getPlatform());
assert t.getMinDiskSize() > 0 : t;
assert t.getMinMemSize() > 0 : t;
}
diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerAllowedArgumentsTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerAllowedArgumentsTest.java
index cebde48..7d1c481 100644
--- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerAllowedArgumentsTest.java
+++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerAllowedArgumentsTest.java
@@ -47,35 +47,34 @@
@SelectJson("argumentslist")
@Consumes(MediaType.APPLICATION_JSON)
public Map<String, ServerAllowedArguments> expected() {
- Map<String, ServerAllowedArguments> result = new LinkedHashMap<String, ServerAllowedArguments>();
- ServerAllowedArguments openvz = ServerAllowedArguments.builder()
- .dataCenters("Amsterdam", "Falkenberg", "New York City", "Stockholm")
- .memorySizes(128, 256, 512, 768, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288)
- .diskSizes(5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 120, 140, 150)
- .cpuCores(1, 2, 3, 4, 5, 6, 7, 8)
- .templates("Centos 5", "Centos 5 64-bit", "Centos 6 32-bit", "Centos 6 64-bit", "Debian 5.0 32-bit",
- "Debian 5.0 64-bit", "Debian 6.0 32-bit", "Debian 6.0 64-bit", "Fedora Core 11", "Fedora Core 11 64-bit",
- "Gentoo", "Gentoo 64-bit", "Scientific Linux 6", "Scientific Linux 6 64-bit", "Slackware 12",
- "Ubuntu 10.04 LTS 32-bit", "Ubuntu 10.04 LTS 64-bit", "Ubuntu 11.04 64-bit")
- .transfers(50, 100, 250, 500, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000)
- .build();
- ServerAllowedArguments xen = ServerAllowedArguments.builder()
- .memorySizes(512, 768, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288, 14336, 16384)
- .diskSizes(5, 10, 20, 30, 40, 50, 80, 100, 120, 140, 150, 160, 160, 200, 250, 300)
- .cpuCores(1, 2, 3, 4, 5, 6, 7, 8)
- .templates("CentOS 5.5 x64", "CentOS 5.5 x86", "Centos 6 x64", "Centos 6 x86", "Debian-6 x64",
- "Debian 5.0.1 x64", "FreeBSD 8.2", "Gentoo 10.1 x64", "Ubuntu 8.04 x64", "Ubuntu 10.04 LTS 64-bit",
- "Ubuntu 10.10 x64", "Ubuntu 11.04 x64", "Windows Server 2008 R2 x64 std",
- "Windows Server 2008 R2 x64 web", "Windows Server 2008 x64 web", "Windows Server 2008 x86 web")
- .transfers(50, 100, 250, 500, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000)
- .dataCenters("Falkenberg")
- .build();
- result.put("Xen", xen);
- result.put("OpenVZ", openvz);
- return result;
+ Map<String, ServerAllowedArguments> result = new LinkedHashMap<String, ServerAllowedArguments>();
+ ServerAllowedArguments openvz = ServerAllowedArguments.builder()
+ .dataCenters("Amsterdam", "Falkenberg", "New York City", "Stockholm")
+ .memorySizes(128, 256, 512, 768, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288)
+ .diskSizes(5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 120, 140, 150)
+ .cpuCores(1, 2, 3, 4, 5, 6, 7, 8)
+ .templates("Centos 5", "Centos 5 64-bit", "Centos 6 32-bit", "Centos 6 64-bit", "Debian 5.0 32-bit",
+ "Debian 5.0 64-bit", "Debian 6.0 32-bit", "Debian 6.0 64-bit", "Fedora Core 11", "Fedora Core 11 64-bit",
+ "Gentoo", "Gentoo 64-bit", "Scientific Linux 6", "Scientific Linux 6 64-bit", "Slackware 12",
+ "Ubuntu 10.04 LTS 32-bit", "Ubuntu 10.04 LTS 64-bit", "Ubuntu 11.04 64-bit")
+ .transfers(50, 100, 250, 500, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000)
+ .build();
+ ServerAllowedArguments xen = ServerAllowedArguments.builder()
+ .memorySizes(512, 768, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288, 14336, 16384)
+ .diskSizes(5, 10, 20, 30, 40, 50, 80, 100, 120, 140, 150, 160, 160, 200, 250, 300)
+ .cpuCores(1, 2, 3, 4, 5, 6, 7, 8)
+ .templates("CentOS 5.5 x64", "CentOS 5.5 x86", "Centos 6 x64", "Centos 6 x86", "Debian-6 x64",
+ "Debian 5.0.1 x64", "FreeBSD 8.2", "Gentoo 10.1 x64", "Ubuntu 8.04 x64", "Ubuntu 10.04 LTS 64-bit",
+ "Ubuntu 10.10 x64", "Ubuntu 11.04 x64", "Windows Server 2008 R2 x64 std",
+ "Windows Server 2008 R2 x64 web", "Windows Server 2008 x64 web", "Windows Server 2008 x86 web")
+ .transfers(50, 100, 250, 500, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000)
+ .dataCenters("Falkenberg")
+ .build();
+ result.put("Xen", xen);
+ result.put("OpenVZ", openvz);
+ return result;
}
-
protected Injector injector() {
return Guice.createInjector(new GleSYSParserModule(), new GsonModule());
}
diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerDetailsTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerDetailsTest.java
new file mode 100644
index 0000000..c0c89eb
--- /dev/null
+++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerDetailsTest.java
@@ -0,0 +1,61 @@
+/**
+ * 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.glesys.parse;
+
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import org.jclouds.glesys.config.GleSYSParserModule;
+import org.jclouds.glesys.domain.Cost;
+import org.jclouds.glesys.domain.ServerCreated;
+import org.jclouds.glesys.domain.ServerCreatedIp;
+import org.jclouds.glesys.domain.ServerDetails;
+import org.jclouds.json.BaseItemParserTest;
+import org.jclouds.json.config.GsonModule;
+import org.jclouds.rest.annotations.SelectJson;
+import org.testng.annotations.Test;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+
+/**
+ * @author Adam Lowe
+ */
+@Test(groups = "unit", testName = "ParseServerDetailsTest")
+public class ParseServerDetailsTest extends BaseItemParserTest<ServerDetails> {
+
+ @Override
+ public String resource() {
+ return "/server_details.json";
+ }
+
+ @Override
+ @SelectJson("server")
+ @Consumes(MediaType.APPLICATION_JSON)
+ public ServerDetails expected() {
+ Cost cost = Cost.builder().amount(6.38).currency("EUR").timePeriod("month").build();
+ return ServerDetails.builder().id("vz1908384").hostname("jclouds-unit").cpuCores(1).
+ memory(128).disk(5).
+ description("unit test server").datacenter("Falkenberg").platform("OpenVZ").cost(cost).build();
+ }
+
+ protected Injector injector() {
+ return Guice.createInjector(new GleSYSParserModule(), new GsonModule());
+ }
+}
diff --git a/sandbox-providers/glesys/src/test/resources/server_details.json b/sandbox-providers/glesys/src/test/resources/server_details.json
new file mode 100644
index 0000000..55ae23a
--- /dev/null
+++ b/sandbox-providers/glesys/src/test/resources/server_details.json
@@ -0,0 +1 @@
+{"response":{"status":{"code":"200","text":"OK"},"server":{"serverid":"vz1908384","hostname":"jclouds-unit","description":"unit test server","cpucores":"1","memory":"128","disk":"5","transfer":"50","template":"Debian 6.0 64-bit","datacenter":"Falkenberg","managedhosting":"no","platform":"OpenVZ","cost":{"amount":6.38,"currency":"EUR","timeperiod":"month"},"iplist":[]},"debug":{"input":{"serverid":"vz1908384"}}}}
\ No newline at end of file
diff --git a/sandbox-providers/glesys/src/test/resources/server_limits.json b/sandbox-providers/glesys/src/test/resources/server_limits.json
new file mode 100644
index 0000000..6939127
--- /dev/null
+++ b/sandbox-providers/glesys/src/test/resources/server_limits.json
@@ -0,0 +1 @@
+{"response":{"status":{"code":"200","text":"OK"},"limits":{"numiptent":{"held":"24","maxheld":"24","barrier":"800","limit":"800","failcnt":0},"numfile":{"held":"91","maxheld":"140","barrier":"4000","limit":"4000","failcnt":0},"dcachesize":{"held":"695143","maxheld":"724260","barrier":"3500000","limit":"4375000","failcnt":0},"numothersock":{"held":"63","maxheld":"66","barrier":"6000","limit":"6000","failcnt":0},"dgramrcvbuf":{"held":"0","maxheld":"0","barrier":"209715200","limit":"262144000","failcnt":0},"othersockbuf":{"held":"4624","maxheld":"13080","barrier":"209715200","limit":"262144000","failcnt":0},"tcprcvbuf":{"held":"32768","maxheld":"32768","barrier":"209715200","limit":"262144000","failcnt":0},"tcpsndbuf":{"held":"34880","maxheld":"34880","barrier":"209715200","limit":"262144000","failcnt":0},"numsiginfo":{"held":"0","maxheld":"15","barrier":"256","limit":"256","failcnt":0},"numpty":{"held":"0","maxheld":"0","barrier":"32","limit":"32","failcnt":0},"numflock":{"held":"1","maxheld":"2","barrier":"376","limit":"412","failcnt":0},"numtcpsock":{"held":"2","maxheld":"2","barrier":"6000","limit":"6000","failcnt":0},"oomguarpages":{"held":"362","maxheld":"464","barrier":"32768","limit":"32768","failcnt":0},"vmguarpages":{"held":"0","maxheld":"0","barrier":"32768","limit":"32768","failcnt":0},"physpages":{"held":"2056","maxheld":"5194","barrier":"0","limit":"9223372036854775807","failcnt":0},"numproc":{"held":"21","maxheld":"33","barrier":"2000","limit":"2000","failcnt":0},"shmpages":{"held":"0","maxheld":"0","barrier":"512000","limit":"512000","failcnt":0},"privvmpages":{"held":"650","maxheld":"1718","barrier":"32768","limit":"32768","failcnt":0},"lockedpages":{"held":"0","maxheld":"0","barrier":"256","limit":"256","failcnt":0},"kmemsize":{"held":"1964946","maxheld":"2932736","barrier":"7680000","limit":"11520000","failcnt":0}},"debug":{"input":{"serverid":"vz1908384"}}}}
\ No newline at end of file
diff --git a/sandbox-providers/virtacore-publiccloud-lax/pom.xml b/sandbox-providers/virtacore-publiccloud-lax/pom.xml
new file mode 100644
index 0000000..6a8b792
--- /dev/null
+++ b/sandbox-providers/virtacore-publiccloud-lax/pom.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.jclouds</groupId>
+ <artifactId>jclouds-project</artifactId>
+ <version>1.3.0-SNAPSHOT</version>
+ <relativePath>../../project/pom.xml</relativePath>
+ </parent>
+ <groupId>org.jclouds.provider</groupId>
+ <artifactId>virtacore-publiccloud-lax</artifactId>
+ <name>jclouds Virtacore Public Cloud LAX provider</name>
+ <description>vCloud implementation targeted to Virtacore's LAX datacenter</description>
+
+ <properties>
+ <test.virtacore-publiccloud-lax.endpoint>https://cloud.lax.virtacore.com/api/</test.virtacore-publiccloud-lax.endpoint>
+ <test.virtacore-publiccloud-lax.api-version>1.0</test.virtacore-publiccloud-lax.api-version>
+ <test.virtacore-publiccloud-lax.build-version>1.5.0.464915</test.virtacore-publiccloud-lax.build-version>
+ <test.virtacore-publiccloud-lax.identity>FIXME_IDENTITY</test.virtacore-publiccloud-lax.identity>
+ <test.virtacore-publiccloud-lax.credential>FIXME_CREDENTIAL</test.virtacore-publiccloud-lax.credential>
+ <test.virtacore-publiccloud-lax.image-id></test.virtacore-publiccloud-lax.image-id>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.jclouds.api</groupId>
+ <artifactId>vcloud</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jclouds.api</groupId>
+ <artifactId>vcloud</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jclouds</groupId>
+ <artifactId>jclouds-core</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jclouds</groupId>
+ <artifactId>jclouds-compute</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jclouds.driver</groupId>
+ <artifactId>jclouds-log4j</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jclouds.driver</groupId>
+ <artifactId>jclouds-sshj</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <profiles>
+ <profile>
+ <id>live</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>integration</id>
+ <phase>integration-test</phase>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <systemPropertyVariables>
+ <test.virtacore-publiccloud-lax.endpoint>${test.virtacore-publiccloud-lax.endpoint}</test.virtacore-publiccloud-lax.endpoint>
+ <test.virtacore-publiccloud-lax.api-version>${test.virtacore-publiccloud-lax.api-version}</test.virtacore-publiccloud-lax.api-version>
+ <test.virtacore-publiccloud-lax.build-version>${test.virtacore-publiccloud-lax.build-version}</test.virtacore-publiccloud-lax.build-version>
+ <test.virtacore-publiccloud-lax.identity>${test.virtacore-publiccloud-lax.identity}</test.virtacore-publiccloud-lax.identity>
+ <test.virtacore-publiccloud-lax.credential>${test.virtacore-publiccloud-lax.credential}</test.virtacore-publiccloud-lax.credential>
+ <test.virtacore-publiccloud-lax.image-id>${test.virtacore-publiccloud-lax.image-id}</test.virtacore-publiccloud-lax.image-id>
+ <test.virtacore-publiccloud-lax.image-id>${test.virtacore-publiccloud-lax.image-id}</test.virtacore-publiccloud-lax.image-id>
+ <test.virtacore-publiccloud-lax.image.login-user>${test.virtacore-publiccloud-lax.image.login-user}</test.virtacore-publiccloud-lax.image.login-user>
+ <test.virtacore-publiccloud-lax.image.authenticate-sudo>${test.virtacore-publiccloud-lax.image.authenticate-sudo}</test.virtacore-publiccloud-lax.image.authenticate-sudo>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Export-Package>org.jclouds.virtacore.publiccloud.*;version="${project.version}"</Export-Package>
+ <Import-Package>org.jclouds.*;version="${project.version}",*</Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
+
diff --git a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressContextBuilder.java b/sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXContextBuilder.java
similarity index 68%
rename from sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressContextBuilder.java
rename to sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXContextBuilder.java
index 05dde33..15ce9ef 100644
--- a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressContextBuilder.java
+++ b/sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXContextBuilder.java
@@ -16,14 +16,14 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.jclouds.virtacore.vcloudexpress;
+package org.jclouds.virtacore.publiccloud;
import java.util.List;
import java.util.Properties;
import org.jclouds.vcloud.VCloudContextBuilder;
-import org.jclouds.virtacore.vcloudexpress.config.VirtacoreVCloudExpressComputeServiceContextModule;
-import org.jclouds.virtacore.vcloudexpress.config.VirtacoreVCloudExpressRestClientModule;
+import org.jclouds.virtacore.publiccloud.config.VirtacorePublicCloudLAXComputeServiceContextModule;
+import org.jclouds.virtacore.publiccloud.config.VirtacorePublicCloudLAXRestClientModule;
import com.google.inject.Module;
@@ -32,20 +32,20 @@
* @author Adrian Cole
*
*/
-public class VirtacoreVCloudExpressContextBuilder extends VCloudContextBuilder {
+public class VirtacorePublicCloudLAXContextBuilder extends VCloudContextBuilder {
- public VirtacoreVCloudExpressContextBuilder(Properties props) {
+ public VirtacorePublicCloudLAXContextBuilder(Properties props) {
super(props);
}
@Override
protected void addContextModule(List<Module> modules) {
- modules.add(new VirtacoreVCloudExpressComputeServiceContextModule());
+ modules.add(new VirtacorePublicCloudLAXComputeServiceContextModule());
}
@Override
protected void addClientModule(List<Module> modules) {
- modules.add(new VirtacoreVCloudExpressRestClientModule());
+ modules.add(new VirtacorePublicCloudLAXRestClientModule());
}
}
diff --git a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressPropertiesBuilder.java b/sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXPropertiesBuilder.java
similarity index 66%
rename from sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressPropertiesBuilder.java
rename to sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXPropertiesBuilder.java
index f428fb6..804de5c 100644
--- a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressPropertiesBuilder.java
+++ b/sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXPropertiesBuilder.java
@@ -16,10 +16,12 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.jclouds.virtacore.vcloudexpress;
+package org.jclouds.virtacore.publiccloud;
+import static org.jclouds.Constants.PROPERTY_BUILD_VERSION;
import static org.jclouds.Constants.PROPERTY_ENDPOINT;
import static org.jclouds.Constants.PROPERTY_ISO3166_CODES;
+import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_CATALOG;
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_NETWORK;
import java.util.Properties;
@@ -30,17 +32,19 @@
*
* @author Adrian Cole
*/
-public class VirtacoreVCloudExpressPropertiesBuilder extends VCloudPropertiesBuilder {
+public class VirtacorePublicCloudLAXPropertiesBuilder extends VCloudPropertiesBuilder {
@Override
protected Properties defaultProperties() {
Properties properties = super.defaultProperties();
- properties.setProperty(PROPERTY_ISO3166_CODES, "US-VA,US-CA");
- properties.setProperty(PROPERTY_ENDPOINT, "https://vcloud.virtacore.com/api");
+ properties.setProperty(PROPERTY_ISO3166_CODES, "US-CA");
+ properties.setProperty(PROPERTY_ENDPOINT, "https://cloud.lax.virtacore.com/api");
+ properties.setProperty(PROPERTY_BUILD_VERSION, "1.5.0.464915");
properties.setProperty(PROPERTY_VCLOUD_DEFAULT_NETWORK, ".*-Public");
+ properties.setProperty(PROPERTY_VCLOUD_DEFAULT_CATALOG, "Virtacore Templates - .*");
return properties;
}
- public VirtacoreVCloudExpressPropertiesBuilder(Properties properties) {
+ public VirtacorePublicCloudLAXPropertiesBuilder(Properties properties) {
super(properties);
}
}
diff --git a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressProviderMetadata.java b/sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXProviderMetadata.java
similarity index 81%
rename from sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressProviderMetadata.java
rename to sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXProviderMetadata.java
index 6093dcb..1f06295 100644
--- a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressProviderMetadata.java
+++ b/sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXProviderMetadata.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.jclouds.virtacore.vcloudexpress;
+package org.jclouds.virtacore.publiccloud;
import com.google.common.collect.ImmutableSet;
@@ -27,18 +27,18 @@
import org.jclouds.providers.ProviderMetadata;
/**
- * Implementation of {@link org.jclouds.types.ProviderMetadata} for Virtacore vCloud Express
+ * Implementation of {@link org.jclouds.types.ProviderMetadata} for Virtacore Public Cloud LAX
*
* @author Adrian Cole
*/
-public class VirtacoreVCloudExpressProviderMetadata extends BaseProviderMetadata {
+public class VirtacorePublicCloudLAXProviderMetadata extends BaseProviderMetadata {
/**
* {@inheritDoc}
*/
@Override
public String getId() {
- return "virtacore-vcloudexpress";
+ return "virtacore-publiccloud-lax";
}
/**
@@ -54,7 +54,7 @@
*/
@Override
public String getName() {
- return "Virtacore vCloud Express";
+ return "Virtacore Public Cloud LAX";
}
/**
@@ -94,7 +94,7 @@
*/
@Override
public URI getApiDocumentation() {
- return URI.create("http://kb.virtacore.com/categories/vCloud+Express/");
+ return URI.create("http://kb.virtacore.com/questions/100/Does+the+Virtacore+Public+Cloud+have+an+API%3F");
}
/**
@@ -102,7 +102,7 @@
*/
@Override
public Set<String> getLinkedServices() {
- return ImmutableSet.of("virtacore-vcloudexpress");
+ return ImmutableSet.of("virtacore-publiccloud-lax", "virtacore-publiccloud-iad");
}
/**
@@ -110,7 +110,7 @@
*/
@Override
public Set<String> getIso3166Codes() {
- return ImmutableSet.of("US-VA","US-CA");
+ return ImmutableSet.of("US-CA");
}
}
diff --git a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/config/VirtacoreVCloudExpressComputeServiceContextModule.java b/sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/config/VirtacorePublicCloudLAXComputeServiceContextModule.java
similarity index 73%
rename from sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/config/VirtacoreVCloudExpressComputeServiceContextModule.java
rename to sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/config/VirtacorePublicCloudLAXComputeServiceContextModule.java
index 2fc6271..d139aaf 100644
--- a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/config/VirtacoreVCloudExpressComputeServiceContextModule.java
+++ b/sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/config/VirtacorePublicCloudLAXComputeServiceContextModule.java
@@ -16,8 +16,11 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.jclouds.virtacore.vcloudexpress.config;
+package org.jclouds.virtacore.publiccloud.config;
+import static org.jclouds.compute.domain.OsFamily.RHEL;
+
+import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.vcloud.compute.config.VCloudComputeServiceContextModule;
import org.jclouds.vcloud.compute.options.VCloudTemplateOptions;
@@ -29,8 +32,14 @@
*
* @author Adrian Cole
*/
-public class VirtacoreVCloudExpressComputeServiceContextModule extends VCloudComputeServiceContextModule {
-
+public class VirtacorePublicCloudLAXComputeServiceContextModule extends VCloudComputeServiceContextModule {
+
+ // CIM ostype does not include version info
+ @Override
+ protected TemplateBuilder provideTemplate(Injector injector, TemplateBuilder template) {
+ return template.osFamily(RHEL).os64Bit(true);
+ }
+
@Override
protected TemplateOptions provideTemplateOptions(Injector injector, TemplateOptions options) {
return options.as(VCloudTemplateOptions.class).ipAddressAllocationMode(IpAddressAllocationMode.POOL);
diff --git a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/config/VirtacoreVCloudExpressRestClientModule.java b/sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/config/VirtacorePublicCloudLAXRestClientModule.java
similarity index 73%
rename from sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/config/VirtacoreVCloudExpressRestClientModule.java
rename to sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/config/VirtacorePublicCloudLAXRestClientModule.java
index 1b1e3b8..e089e92 100644
--- a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/config/VirtacoreVCloudExpressRestClientModule.java
+++ b/sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/config/VirtacorePublicCloudLAXRestClientModule.java
@@ -16,13 +16,11 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.jclouds.virtacore.vcloudexpress.config;
+package org.jclouds.virtacore.publiccloud.config;
import org.jclouds.http.RequiresHttp;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.vcloud.config.VCloudRestClientModule;
-import org.jclouds.vcloud.filters.SetVCloudTokenCookie;
-import org.jclouds.virtacore.vcloudexpress.filters.SetVCloudTokenCookieAndAuthorizationHeader;
/**
*
@@ -30,12 +28,11 @@
*/
@RequiresHttp
@ConfiguresRestClient
-public class VirtacoreVCloudExpressRestClientModule extends VCloudRestClientModule {
+public class VirtacorePublicCloudLAXRestClientModule extends VCloudRestClientModule {
@Override
protected void configure() {
super.configure();
- bind(SetVCloudTokenCookie.class).to(SetVCloudTokenCookieAndAuthorizationHeader.class);
}
}
diff --git a/sandbox-providers/virtacore-publiccloud-lax/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata b/sandbox-providers/virtacore-publiccloud-lax/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
new file mode 100644
index 0000000..5290e8f
--- /dev/null
+++ b/sandbox-providers/virtacore-publiccloud-lax/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
@@ -0,0 +1 @@
+org.jclouds.virtacore.publiccloud.VirtacorePublicCloudLAXProviderMetadata
diff --git a/sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressProviderTest.java b/sandbox-providers/virtacore-publiccloud-lax/src/test/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXProviderTest.java
similarity index 69%
rename from sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressProviderTest.java
rename to sandbox-providers/virtacore-publiccloud-lax/src/test/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXProviderTest.java
index 8965a26..687b7d9 100644
--- a/sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressProviderTest.java
+++ b/sandbox-providers/virtacore-publiccloud-lax/src/test/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXProviderTest.java
@@ -16,21 +16,21 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.jclouds.virtacore.vcloudexpress;
+package org.jclouds.virtacore.publiccloud;
import org.jclouds.providers.BaseProviderMetadataTest;
import org.jclouds.providers.ProviderMetadata;
-import org.jclouds.virtacore.vcloudexpress.VirtacoreVCloudExpressProviderMetadata;
+import org.jclouds.virtacore.publiccloud.VirtacorePublicCloudLAXProviderMetadata;
import org.testng.annotations.Test;
/**
*
* @author Adrian Cole
*/
-@Test(groups = "unit", testName = "VirtacoreVCloudExpressProviderTest")
-public class VirtacoreVCloudExpressProviderTest extends BaseProviderMetadataTest {
+@Test(groups = "unit", testName = "VirtacorePublicCloudLAXProviderTest")
+public class VirtacorePublicCloudLAXProviderTest extends BaseProviderMetadataTest {
- public VirtacoreVCloudExpressProviderTest() {
- super(new VirtacoreVCloudExpressProviderMetadata(), ProviderMetadata.COMPUTE_TYPE);
+ public VirtacorePublicCloudLAXProviderTest() {
+ super(new VirtacorePublicCloudLAXProviderMetadata(), ProviderMetadata.COMPUTE_TYPE);
}
}
diff --git a/sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/compute/VirtacoreVCloudExpressComputeServiceLiveTest.java b/sandbox-providers/virtacore-publiccloud-lax/src/test/java/org/jclouds/virtacore/publiccloud/compute/VirtacorePublicCloudLAXComputeServiceLiveTest.java
similarity index 74%
rename from sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/compute/VirtacoreVCloudExpressComputeServiceLiveTest.java
rename to sandbox-providers/virtacore-publiccloud-lax/src/test/java/org/jclouds/virtacore/publiccloud/compute/VirtacorePublicCloudLAXComputeServiceLiveTest.java
index a172d5f..ae8c153 100644
--- a/sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/compute/VirtacoreVCloudExpressComputeServiceLiveTest.java
+++ b/sandbox-providers/virtacore-publiccloud-lax/src/test/java/org/jclouds/virtacore/publiccloud/compute/VirtacorePublicCloudLAXComputeServiceLiveTest.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.jclouds.virtacore.vcloudexpress.compute;
+package org.jclouds.virtacore.publiccloud.compute;
import org.jclouds.vcloud.compute.VCloudComputeServiceLiveTest;
import org.testng.annotations.Test;
@@ -27,14 +27,9 @@
* @author Adrian Cole
*/
@Test(groups = "live", enabled = true, singleThreaded = true)
-public class VirtacoreVCloudExpressComputeServiceLiveTest extends VCloudComputeServiceLiveTest {
- public VirtacoreVCloudExpressComputeServiceLiveTest() {
- provider = "virtacore-vcloudexpress";
- }
-
- @Override
- public void setServiceDefaults() {
- group = "director";
+public class VirtacorePublicCloudLAXComputeServiceLiveTest extends VCloudComputeServiceLiveTest {
+ public VirtacorePublicCloudLAXComputeServiceLiveTest() {
+ provider = "virtacore-publiccloud-lax";
}
}
diff --git a/sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/compute/VirtacoreVCloudExpressTemplateBuilderLiveTest.java b/sandbox-providers/virtacore-publiccloud-lax/src/test/java/org/jclouds/virtacore/publiccloud/compute/VirtacorePublicCloudLAXTemplateBuilderLiveTest.java
similarity index 68%
rename from sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/compute/VirtacoreVCloudExpressTemplateBuilderLiveTest.java
rename to sandbox-providers/virtacore-publiccloud-lax/src/test/java/org/jclouds/virtacore/publiccloud/compute/VirtacorePublicCloudLAXTemplateBuilderLiveTest.java
index d45cfef..4f8b410 100644
--- a/sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/compute/VirtacoreVCloudExpressTemplateBuilderLiveTest.java
+++ b/sandbox-providers/virtacore-publiccloud-lax/src/test/java/org/jclouds/virtacore/publiccloud/compute/VirtacorePublicCloudLAXTemplateBuilderLiveTest.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.jclouds.virtacore.vcloudexpress.compute;
+package org.jclouds.virtacore.publiccloud.compute;
import static org.jclouds.compute.util.ComputeServiceUtils.getCores;
import static org.testng.Assert.assertEquals;
@@ -31,6 +31,7 @@
import org.testng.annotations.Test;
import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableSet;
/**
@@ -38,42 +39,45 @@
* @author Adrian Cole
*/
@Test(groups = "live")
-public class VirtacoreVCloudExpressTemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest {
+public class VirtacorePublicCloudLAXTemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest {
- public VirtacoreVCloudExpressTemplateBuilderLiveTest() {
- provider = "virtacore-vcloudexpress";
+ public VirtacorePublicCloudLAXTemplateBuilderLiveTest() {
+ provider = "virtacore-publiccloud-lax";
}
@Override
protected Predicate<OsFamilyVersion64Bit> defineUnsupportedOperatingSystems() {
- return new Predicate<OsFamilyVersion64Bit>() {
+ return Predicates.not(new Predicate<OsFamilyVersion64Bit>() {
@Override
public boolean apply(OsFamilyVersion64Bit input) {
switch (input.family) {
- case UBUNTU:
- return !input.version.equals("");
- case RHEL:
- return !input.version.equals("");
- default:
- return true;
+ case RHEL:
+ return input.version.equals("");
+ case SUSE:
+ // vCloud Connector
+ return input.version.equals("") && input.is64Bit;
+ default:
+ return false;
}
}
- };
+ });
}
+ // NOTE: almost all virtacore templates are dual-network
@Override
public void testDefaultTemplateBuilder() throws IOException {
Template defaultTemplate = context.getComputeService().templateBuilder().build();
+ assertEquals(defaultTemplate.getImage().getName(), "RHEL 5.6 64bit");
assertEquals(defaultTemplate.getImage().getOperatingSystem().getVersion(), "");
assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true);
- assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU);
- assertEquals(getCores(defaultTemplate.getHardware()), 1.0d);
+ assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.RHEL);
+ assertEquals(getCores(defaultTemplate.getHardware()), 2.0d);
}
@Override
protected Set<String> getIso3166Codes() {
- return ImmutableSet.<String> of("US-VA", "US-CA");
+ return ImmutableSet.<String> of("US-CA");
}
}
diff --git a/sandbox-providers/virtacore-vcloudexpress/src/test/resources/log4j.xml b/sandbox-providers/virtacore-publiccloud-lax/src/test/resources/log4j.xml
similarity index 100%
rename from sandbox-providers/virtacore-vcloudexpress/src/test/resources/log4j.xml
rename to sandbox-providers/virtacore-publiccloud-lax/src/test/resources/log4j.xml
diff --git a/sandbox-providers/virtacore-vcloudexpress/pom.xml b/sandbox-providers/virtacore-vcloudexpress/pom.xml
deleted file mode 100644
index a2a0d29..0000000
--- a/sandbox-providers/virtacore-vcloudexpress/pom.xml
+++ /dev/null
@@ -1,120 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- 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.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.jclouds</groupId>
- <artifactId>jclouds-project</artifactId>
- <version>1.3.0-SNAPSHOT</version>
- <relativePath>../../project/pom.xml</relativePath>
- </parent>
- <groupId>org.jclouds.provider</groupId>
- <artifactId>virtacore-vcloudexpress</artifactId>
- <name>jclouds Virtacore vCloud Express provider</name>
- <description>vCloud implementation targeted to Virtacore</description>
-
- <properties>
- <test.virtacore-vcloudexpress.endpoint>https://vcloud.virtacore.com/api</test.virtacore-vcloudexpress.endpoint>
- <test.virtacore-vcloudexpress.api-version>1.0</test.virtacore-vcloudexpress.api-version>
- <test.virtacore-vcloudexpress.build-version></test.virtacore-vcloudexpress.build-version>
- <test.virtacore-vcloudexpress.identity>FIXME_IDENTITY</test.virtacore-vcloudexpress.identity>
- <test.virtacore-vcloudexpress.credential>FIXME_CREDENTIAL</test.virtacore-vcloudexpress.credential>
- <test.virtacore-vcloudexpress.image-id></test.virtacore-vcloudexpress.image-id>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>org.jclouds.api</groupId>
- <artifactId>vcloud</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.jclouds.api</groupId>
- <artifactId>vcloud</artifactId>
- <version>${project.version}</version>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.jclouds</groupId>
- <artifactId>jclouds-core</artifactId>
- <version>${project.version}</version>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.jclouds</groupId>
- <artifactId>jclouds-compute</artifactId>
- <version>${project.version}</version>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.jclouds.driver</groupId>
- <artifactId>jclouds-log4j</artifactId>
- <version>${project.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.jclouds.driver</groupId>
- <artifactId>jclouds-sshj</artifactId>
- <version>${project.version}</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
- <profiles>
- <profile>
- <id>live</id>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <executions>
- <execution>
- <id>integration</id>
- <phase>integration-test</phase>
- <goals>
- <goal>test</goal>
- </goals>
- <configuration>
- <systemPropertyVariables>
- <test.virtacore-vcloudexpress.endpoint>${test.virtacore-vcloudexpress.endpoint}</test.virtacore-vcloudexpress.endpoint>
- <test.virtacore-vcloudexpress.api-version>${test.virtacore-vcloudexpress.api-version}</test.virtacore-vcloudexpress.api-version>
- <test.virtacore-vcloudexpress.build-version>${test.virtacore-vcloudexpress.build-version}</test.virtacore-vcloudexpress.build-version>
- <test.virtacore-vcloudexpress.identity>${test.virtacore-vcloudexpress.identity}</test.virtacore-vcloudexpress.identity>
- <test.virtacore-vcloudexpress.credential>${test.virtacore-vcloudexpress.credential}</test.virtacore-vcloudexpress.credential>
- <test.virtacore-vcloudexpress.image-id>${test.virtacore-vcloudexpress.image-id}</test.virtacore-vcloudexpress.image-id>
- </systemPropertyVariables>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
- </profile>
- </profiles>
-
-
-</project>
-
diff --git a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/filters/SetVCloudTokenCookieAndAuthorizationHeader.java b/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/filters/SetVCloudTokenCookieAndAuthorizationHeader.java
deleted file mode 100644
index c87597b..0000000
--- a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/filters/SetVCloudTokenCookieAndAuthorizationHeader.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * 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.virtacore.vcloudexpress.filters;
-
-import javax.inject.Inject;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-
-import org.jclouds.http.HttpException;
-import org.jclouds.http.HttpRequest;
-import org.jclouds.http.utils.ModifyRequest;
-import org.jclouds.vcloud.VCloudToken;
-import org.jclouds.vcloud.filters.SetVCloudTokenCookie;
-
-/**
- * Adds the VCloud Token to the request as a cookie
- *
- * @author Adrian Cole
- *
- */
-@Singleton
-public class SetVCloudTokenCookieAndAuthorizationHeader extends SetVCloudTokenCookie {
-
- private final Provider<String> vcloudTokenProvider;
-
- @Inject
- public SetVCloudTokenCookieAndAuthorizationHeader(@VCloudToken Provider<String> authTokenProvider) {
- super(authTokenProvider);
- this.vcloudTokenProvider = authTokenProvider;
- }
-
- @Override
- public HttpRequest filter(HttpRequest request) throws HttpException {
- return ModifyRequest.replaceHeader(super.filter(request), "x-vcloud-authorization", vcloudTokenProvider.get());
- }
-
-}
\ No newline at end of file
diff --git a/sandbox-providers/virtacore-vcloudexpress/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata b/sandbox-providers/virtacore-vcloudexpress/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
deleted file mode 100644
index 8505807..0000000
--- a/sandbox-providers/virtacore-vcloudexpress/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
+++ /dev/null
@@ -1 +0,0 @@
-org.jclouds.virtacore.vcloudexpress.VirtacoreVCloudExpressProviderMetadata