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 &quot;(com.vmware.vcloud.entity.vapp:d3a1f2cd-d07b-4ddc-bf7b-fb7468b4d95a)&quot;.\" 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