Merge branch 'master' into 1.5.x

* master:
  enum is not a sustainable way to refer to address blocks
  Issue 894:update to guava 12.0-rc2
  make FutureIterables covariant compatible + update tests
  implemented image extension
  Issue 895: Adjusting name and description of openstack-nova-ec2 maven module
  Issue 895: Correcting placement of rest client binding
  Issue 895: Filtering out non-MACHINE images from Nova-EC2 responses (note 2009-04-04 EC2 API didn't support filtering at the machine end)
  Exposing contents of DescribeImagesResponseHandler to subclasses
  Adjusting openstack-nova-ec2 to handle extended volume status fields (by discarding the extra information)
  Exposing fields of CreateVolumeResponseHandler to subclasses
diff --git a/apis/cloudloadbalancers/src/main/java/org/jclouds/cloudloadbalancers/loadbalancer/strategy/CloudLoadBalancersListLoadBalancersStrategy.java b/apis/cloudloadbalancers/src/main/java/org/jclouds/cloudloadbalancers/loadbalancer/strategy/CloudLoadBalancersListLoadBalancersStrategy.java
index a720ce7..9154689 100644
--- a/apis/cloudloadbalancers/src/main/java/org/jclouds/cloudloadbalancers/loadbalancer/strategy/CloudLoadBalancersListLoadBalancersStrategy.java
+++ b/apis/cloudloadbalancers/src/main/java/org/jclouds/cloudloadbalancers/loadbalancer/strategy/CloudLoadBalancersListLoadBalancersStrategy.java
@@ -72,7 +72,7 @@
 
    @Override
    public Iterable<? extends LoadBalancerMetadata> listLoadBalancers() {
-      return transform(concat(transformParallel(regions.get(), new Function<String, Future<Set<LoadBalancer>>>() {
+      return transform(concat(transformParallel(regions.get(), new Function<String, Future<? extends Set<LoadBalancer>>>() {
 
          @Override
          public ListenableFuture<Set<LoadBalancer>> apply(String from) {
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 52ade29..74327d0 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
@@ -56,6 +56,7 @@
 import org.jclouds.domain.Location;
 import org.jclouds.domain.LoginCredentials;
 import org.jclouds.logging.Logger;
+import org.jclouds.util.Iterables2;
 
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
@@ -170,8 +171,8 @@
     */
    @Override
    public Iterable<DriveInfo> listImages() {
-      Iterable<DriveInfo> drives = transformParallel(client.listStandardDrives(),
-            new Function<String, Future<DriveInfo>>() {
+      Iterable<? extends DriveInfo> drives = transformParallel(client.listStandardDrives(),
+            new Function<String, Future<? extends DriveInfo>>() {
 
                @Override
                public Future<DriveInfo> apply(String input) {
@@ -190,7 +191,7 @@
                   return "seedDriveCache()";
                }
             }, executor, null, logger, "drives");
-      return filter(drives, PREINSTALLED_DISK);
+      return Iterables2.concreteCopy(filter(drives, PREINSTALLED_DISK));
    }
 
    @SuppressWarnings("unchecked")
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java b/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java
index 3ea04e1..c30ec5a 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java
@@ -25,8 +25,8 @@
 import static org.jclouds.util.Preconditions2.checkNotEmpty;
 
 import java.util.Map;
-import java.util.Set;
 import java.util.Map.Entry;
+import java.util.Set;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.atomic.AtomicReference;
@@ -39,6 +39,7 @@
 import org.jclouds.aws.util.AWSUtils;
 import org.jclouds.collect.Memoized;
 import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.compute.ImageExtension;
 import org.jclouds.compute.callables.RunScriptOnNode;
 import org.jclouds.compute.domain.Hardware;
 import org.jclouds.compute.domain.Image;
@@ -69,12 +70,13 @@
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Function;
+import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;
 import com.google.common.cache.LoadingCache;
 import com.google.common.collect.ImmutableMultimap;
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableMultimap.Builder;
+import com.google.common.collect.ImmutableSet;
 import com.google.inject.Inject;
 
 /**
@@ -101,12 +103,13 @@
          RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
          PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
          @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, EC2Client ec2Client,
-         ConcurrentMap<RegionAndName, KeyPair> credentialsMap, @Named("SECURITY") LoadingCache<RegionAndName, String> securityGroupMap) {
+         ConcurrentMap<RegionAndName, KeyPair> credentialsMap, @Named("SECURITY") LoadingCache<RegionAndName, String> securityGroupMap,
+         Optional<ImageExtension> imageExtension) {
       super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
             runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, stopNodeStrategy,
             templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, nodeSuspended,
             initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials, timeouts,
-            executor);
+            executor, imageExtension);
       this.ec2Client = ec2Client;
       this.credentialsMap = credentialsMap;
       this.securityGroupMap = securityGroupMap;
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/DescribeImagesParallel.java b/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/DescribeImagesParallel.java
index 61abb02..f080408 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/DescribeImagesParallel.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/DescribeImagesParallel.java
@@ -65,7 +65,7 @@
             Iterable<Entry<String, DescribeImagesOptions>> queries) {
       return concat(transformParallel(
                queries,
-               new Function<Entry<String, DescribeImagesOptions>, Future<Set<? extends org.jclouds.ec2.domain.Image>>>() {
+               new Function<Entry<String, DescribeImagesOptions>, Future<? extends Set<? extends org.jclouds.ec2.domain.Image>>>() {
 
                   @Override
                   public Future<Set<? extends org.jclouds.ec2.domain.Image>> apply(
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/EC2ListNodesStrategy.java b/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/EC2ListNodesStrategy.java
index 0ac45bd..2c0d1d0 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/EC2ListNodesStrategy.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/EC2ListNodesStrategy.java
@@ -92,7 +92,7 @@
 
    protected Iterable<? extends RunningInstance> pollRunningInstances() {
       Iterable<? extends Set<? extends Reservation<? extends RunningInstance>>> reservations = transformParallel(
-               regions.get(), new Function<String, Future<Set<? extends Reservation<? extends RunningInstance>>>>() {
+               regions.get(), new Function<String, Future<? extends Set<? extends Reservation<? extends RunningInstance>>>>() {
 
                   @Override
                   public Future<Set<? extends Reservation<? extends RunningInstance>>> apply(String from) {
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/xml/CreateVolumeResponseHandler.java b/apis/ec2/src/main/java/org/jclouds/ec2/xml/CreateVolumeResponseHandler.java
index e0c92b2..2416e5e 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/xml/CreateVolumeResponseHandler.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/xml/CreateVolumeResponseHandler.java
@@ -50,7 +50,7 @@
  * @author Adrian Cole
  */
 public class CreateVolumeResponseHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Volume> {
-   private StringBuilder currentText = new StringBuilder();
+   protected StringBuilder currentText = new StringBuilder();
 
    @Resource
    protected Logger logger = Logger.NULL;
@@ -58,7 +58,7 @@
    protected DateService dateService;
    @Inject
    @Region
-   Supplier<String> defaultRegion;
+   protected Supplier<String> defaultRegion;
    @Inject
    @Zone
    protected Supplier<Map<String, Supplier<Set<String>>>> regionToZonesSupplier;
@@ -66,23 +66,23 @@
    @Zone
    protected Supplier<Set<String>> zonesSupplier;
    
-   private String id;
-   private int size;
-   private String snapshotId;
-   private String availabilityZone;
-   private Volume.Status volumeStatus;
-   private Date createTime;
-   private Set<Attachment> attachments = Sets.newLinkedHashSet();
+   protected String id;
+   protected int size;
+   protected String snapshotId;
+   protected String availabilityZone;
+   protected Volume.Status volumeStatus;
+   protected Date createTime;
+   protected Set<Attachment> attachments = Sets.newLinkedHashSet();
 
-   private String volumeId;
-   private String instanceId;
-   private String device;
-   private Attachment.Status attachmentStatus;
-   private Date attachTime;
+   protected String volumeId;
+   protected String instanceId;
+   protected String device;
+   protected Attachment.Status attachmentStatus;
+   protected Date attachTime;
 
-   private boolean inAttachmentSet;
+   protected boolean inAttachmentSet;
 
-   private String region;
+   protected String region;
 
    public Volume getResult() {
       return newVolume();
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/xml/DescribeImagesResponseHandler.java b/apis/ec2/src/main/java/org/jclouds/ec2/xml/DescribeImagesResponseHandler.java
index 2e92af7..9b78e7d 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/xml/DescribeImagesResponseHandler.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/xml/DescribeImagesResponseHandler.java
@@ -61,7 +61,7 @@
    @Resource
    protected Logger logger = Logger.NULL;
 
-   private Set<Image> contents = Sets.newLinkedHashSet();
+   protected Set<Image> contents = Sets.newLinkedHashSet();
    private StringBuilder currentText = new StringBuilder();
    private final Supplier<String> defaultRegion;
 
diff --git a/apis/elasticstack/src/main/java/org/jclouds/elasticstack/compute/ElasticStackComputeServiceAdapter.java b/apis/elasticstack/src/main/java/org/jclouds/elasticstack/compute/ElasticStackComputeServiceAdapter.java
index 6211969..0403679 100644
--- a/apis/elasticstack/src/main/java/org/jclouds/elasticstack/compute/ElasticStackComputeServiceAdapter.java
+++ b/apis/elasticstack/src/main/java/org/jclouds/elasticstack/compute/ElasticStackComputeServiceAdapter.java
@@ -58,6 +58,7 @@
 import org.jclouds.elasticstack.domain.WellKnownImage;
 import org.jclouds.elasticstack.reference.ElasticStackConstants;
 import org.jclouds.logging.Logger;
+import org.jclouds.util.Iterables2;
 
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
@@ -162,11 +163,11 @@
     */
    @Override
    public Iterable<DriveInfo> listImages() {
-      Iterable<DriveInfo> drives = transformParallel(preinstalledImages.keySet(),
-            new Function<String, Future<DriveInfo>>() {
+      Iterable<? extends DriveInfo> drives = transformParallel(preinstalledImages.keySet(),
+            new Function<String, Future<? extends DriveInfo>>() {
 
                @Override
-               public Future<DriveInfo> apply(String input) {
+               public Future<? extends DriveInfo> apply(String input) {
                   try {
                      return Futures.immediateFuture(cache.getUnchecked(input));
                   } catch (CacheLoader.InvalidCacheLoadException e) {
@@ -183,7 +184,7 @@
                }
 
             }, executor, null, logger, "drives");
-      return filter(drives, notNull());
+      return Iterables2.concreteCopy(filter(drives, notNull()));
    }
 
    @SuppressWarnings("unchecked")
diff --git a/apis/openstack-nova-ec2/pom.xml b/apis/openstack-nova-ec2/pom.xml
index 647c100..e3e6ccd 100644
--- a/apis/openstack-nova-ec2/pom.xml
+++ b/apis/openstack-nova-ec2/pom.xml
@@ -29,8 +29,8 @@
   </parent>
   <groupId>org.jclouds.api</groupId>
   <artifactId>openstack-nova-ec2</artifactId>
-  <name>jclouds Eucalyptus api</name>
-  <description>EC2 implementation based on Eucalyptus</description>
+  <name>jclouds openstack-nova-ec2 api</name>
+  <description>EC2 interface to Openstack Nova</description>
   <packaging>bundle</packaging>
 
   <properties>
diff --git a/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/config/NovaEC2RestClientModule.java b/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/config/NovaEC2RestClientModule.java
index f2ff664..6ea5685 100644
--- a/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/config/NovaEC2RestClientModule.java
+++ b/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/config/NovaEC2RestClientModule.java
@@ -22,10 +22,14 @@
 import org.jclouds.ec2.EC2Client;
 import org.jclouds.ec2.config.EC2RestClientModule;
 import org.jclouds.ec2.suppliers.DescribeAvailabilityZonesInRegion;
+import org.jclouds.ec2.xml.CreateVolumeResponseHandler;
+import org.jclouds.ec2.xml.DescribeImagesResponseHandler;
 import org.jclouds.location.config.LocationModule;
 import org.jclouds.location.suppliers.RegionIdToZoneIdsSupplier;
 import org.jclouds.location.suppliers.ZoneIdsSupplier;
 import org.jclouds.location.suppliers.derived.ZoneIdsFromRegionIdToZoneIdsValues;
+import org.jclouds.openstack.nova.ec2.xml.NovaCreateVolumeResponseHandler;
+import org.jclouds.openstack.nova.ec2.xml.NovaDescribeImagesResponseHandler;
 import org.jclouds.rest.ConfiguresRestClient;
 
 import com.google.inject.Scopes;
@@ -42,6 +46,13 @@
    }
 
    @Override
+   protected void configure() {
+      super.configure();
+      bind(CreateVolumeResponseHandler.class).to(NovaCreateVolumeResponseHandler.class).in(Scopes.SINGLETON);
+      bind(DescribeImagesResponseHandler.class).to(NovaDescribeImagesResponseHandler.class);
+   }
+
+   @Override
    protected void installLocations() {
       install(new LocationModule());
       bind(RegionIdToZoneIdsSupplier.class).to(DescribeAvailabilityZonesInRegion.class).in(Scopes.SINGLETON);
diff --git a/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/xml/NovaCreateVolumeResponseHandler.java b/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/xml/NovaCreateVolumeResponseHandler.java
new file mode 100644
index 0000000..db6b7c4
--- /dev/null
+++ b/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/xml/NovaCreateVolumeResponseHandler.java
@@ -0,0 +1,48 @@
+/**
+ * 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.ec2.xml;
+
+import org.jclouds.ec2.domain.Attachment;
+import org.jclouds.ec2.domain.Volume;
+import org.jclouds.ec2.xml.CreateVolumeResponseHandler;
+
+/**
+ *
+ * @author Adam lowe
+ */
+public class NovaCreateVolumeResponseHandler extends CreateVolumeResponseHandler {
+   
+   public void endElement(String uri, String name, String qName) {
+      if (qName.equals("status")) {
+         String statusString = currentText.toString().trim();
+         if (statusString.contains(" ")) {
+            statusString = statusString.substring(0, statusString.indexOf(' '));
+         }
+         if (inAttachmentSet) {
+            attachmentStatus = Attachment.Status.fromValue(statusString);
+         } else {
+            volumeStatus = Volume.Status.fromValue(statusString);
+         }
+         currentText = new StringBuilder();
+      } else {
+         super.endElement(uri, name, qName);
+      }
+   }
+
+}
diff --git a/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/xml/NovaDescribeImagesResponseHandler.java b/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/xml/NovaDescribeImagesResponseHandler.java
new file mode 100644
index 0000000..6c0945d
--- /dev/null
+++ b/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/xml/NovaDescribeImagesResponseHandler.java
@@ -0,0 +1,54 @@
+/**
+ * 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.ec2.xml;
+
+import java.util.Set;
+
+import javax.inject.Inject;
+
+import org.jclouds.ec2.domain.Image;
+import org.jclouds.ec2.domain.Image.ImageType;
+import org.jclouds.ec2.xml.DescribeImagesResponseHandler;
+import org.jclouds.location.Region;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+
+/**
+ * Adjusted to filter out non-MACHINE images
+ *
+ * @author Adam Lowe
+ */
+public class NovaDescribeImagesResponseHandler extends DescribeImagesResponseHandler {
+   @Inject
+   public NovaDescribeImagesResponseHandler(@Region Supplier<String> defaultRegion) {
+      super(defaultRegion);
+   }
+
+   public Set<Image> getResult() {
+      return ImmutableSet.copyOf(Iterables.filter(contents, new Predicate<Image>() {
+         @Override
+         public boolean apply(Image image) {
+            return image.getImageType() == ImageType.MACHINE;
+         }
+      }));
+   }
+}
diff --git a/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/internal/BaseNovaEC2RestClientExpectTest.java b/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/internal/BaseNovaEC2RestClientExpectTest.java
new file mode 100644
index 0000000..5f34f76
--- /dev/null
+++ b/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/internal/BaseNovaEC2RestClientExpectTest.java
@@ -0,0 +1,54 @@
+package org.jclouds.openstack.nova.ec2.internal;
+
+import java.net.URI;
+
+import javax.inject.Named;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.Constants;
+import org.jclouds.date.DateService;
+import org.jclouds.date.internal.SimpleDateFormatDateService;
+import org.jclouds.ec2.EC2Client;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.nova.ec2.config.NovaEC2RestClientModule;
+import org.jclouds.rest.ConfiguresRestClient;
+import org.jclouds.rest.internal.BaseRestClientExpectTest;
+
+import com.google.common.collect.ImmutableMultimap;
+import com.google.inject.Module;
+import com.google.inject.Provides;
+
+public abstract class BaseNovaEC2RestClientExpectTest extends BaseRestClientExpectTest<EC2Client> {
+   protected static final String CONSTANT_DATE = "2012-04-16T15:54:08.897Z";
+   protected DateService dateService = new SimpleDateFormatDateService();
+   protected URI endpoint = URI.create("http://localhost:8773/services/Cloud/");
+   
+   protected HttpRequest describeAvailabilityZonesRequest = HttpRequest.builder().method("POST")
+         .endpoint(endpoint)
+         .headers(ImmutableMultimap.of("Host", "localhost:8773"))
+         .payload(payloadFromStringWithContentType("Action=DescribeAvailabilityZones&Signature=S3fa5fybw4KAq4o11IpKHlqwx3cVJdKfeAKw3FIJYvM%3D&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2012-04-16T15%3A54%3A08.897Z&Version=2009-04-04&AWSAccessKeyId=identity", MediaType.APPLICATION_FORM_URLENCODED))
+         .build();
+   protected HttpResponse describeAvailabilityZonesResponse = HttpResponse.builder()
+         .statusCode(200).payload(payloadFromResourceWithContentType("/nova_ec2_availabilityZones.xml", MediaType.APPLICATION_XML)).build();
+
+
+   public BaseNovaEC2RestClientExpectTest() {
+      provider = "openstack-nova-ec2";
+   }
+
+   @ConfiguresRestClient
+   private static final class TestNovaEC2RestClientModule extends NovaEC2RestClientModule {
+      @Override
+      @Provides
+      protected String provideTimeStamp(final DateService dateService,
+                                        @Named(Constants.PROPERTY_SESSION_INTERVAL) final int expiration) {
+         return CONSTANT_DATE;
+      }
+   }
+
+   @Override
+   protected Module createModule() {
+      return new TestNovaEC2RestClientModule();
+   }
+}
diff --git a/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/services/NovaEC2AMIClientTest.java b/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/services/NovaEC2AMIClientTest.java
new file mode 100644
index 0000000..81b15a2
--- /dev/null
+++ b/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/services/NovaEC2AMIClientTest.java
@@ -0,0 +1,58 @@
+/**
+ * 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.ec2.services;
+
+import static org.testng.Assert.assertEquals;
+
+import java.net.URI;
+import java.util.Set;
+
+import org.jclouds.ec2.domain.Image;
+import org.jclouds.ec2.services.AMIClient;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.nova.ec2.internal.BaseNovaEC2RestClientExpectTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMultimap;
+
+/**
+ * @author Adam Lowe
+ */
+@Test(groups = "unit", testName = "NovaEC2ElasticBlockStoreClientTest")
+public class NovaEC2AMIClientTest extends BaseNovaEC2RestClientExpectTest {
+
+   public void testDescribeImagesWithNonMachineTypes() {
+      AMIClient client = requestsSendResponses(
+            describeAvailabilityZonesRequest,
+            describeAvailabilityZonesResponse,
+            HttpRequest.builder().method("POST")
+                  .endpoint(URI.create("http://localhost:8773/services/Cloud/"))
+                  .headers(ImmutableMultimap.of("Host", "localhost:8773"))
+                  .payload(payloadFromStringWithContentType("Action=DescribeImages&Signature=Z3q3jSutwlfgvbcINT0Ed3AjrjxM4WMvQloXu%2F1kd40%3D&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2012-04-16T15%3A54%3A08.897Z&Version=2009-04-04&AWSAccessKeyId=identity", "application/x-www-form-urlencoded")).build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/nova_ec2_images_with_ramdisk.xml")).build()
+      ).getAMIServices();
+
+      Set<? extends Image> images = client.describeImagesInRegion("nova");
+      
+      assertEquals(images.size(), 1);
+      
+   }
+
+}
diff --git a/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/services/NovaEC2ElasticBlockStoreClientTest.java b/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/services/NovaEC2ElasticBlockStoreClientTest.java
new file mode 100644
index 0000000..021ee90
--- /dev/null
+++ b/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/services/NovaEC2ElasticBlockStoreClientTest.java
@@ -0,0 +1,68 @@
+/**
+ * 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.ec2.services;
+
+import static org.testng.Assert.assertEquals;
+
+import java.net.URI;
+import java.util.Set;
+
+import org.jclouds.ec2.domain.Attachment;
+import org.jclouds.ec2.domain.Volume;
+import org.jclouds.ec2.services.ElasticBlockStoreClient;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.nova.ec2.internal.BaseNovaEC2RestClientExpectTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * @author Adam Lowe
+ */
+@Test(groups = "unit", testName = "NovaEC2ElasticBlockStoreClientTest")
+public class NovaEC2ElasticBlockStoreClientTest extends BaseNovaEC2RestClientExpectTest {
+
+   public void testDescribeVolumesWithNovaEC2Status() {
+      ElasticBlockStoreClient client = requestsSendResponses(
+            describeAvailabilityZonesRequest,
+            describeAvailabilityZonesResponse,
+            HttpRequest.builder().method("POST")
+                  .endpoint(URI.create("http://localhost:8773/services/Cloud/"))
+                  .headers(ImmutableMultimap.of("Host", "localhost:8773"))
+                  .payload(payloadFromStringWithContentType("Action=DescribeVolumes&Signature=AvRznSzGExM%2Buaj2JJj66wq4v4f%2BakicyLooRDtC0t0%3D&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2012-04-16T15%3A54%3A08.897Z&Version=2009-04-04&AWSAccessKeyId=identity", "application/x-www-form-urlencoded")).build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/nova_ec2_describe_volumes.xml")).build()
+      ).getElasticBlockStoreServices();
+
+      Set<Volume> expected = ImmutableSet.of(Volume
+            .builder()
+            .status(Volume.Status.AVAILABLE)
+            .availabilityZone("nova")
+            .region("nova")
+            .id("vol-00000007")
+            .size(1)
+            .attachments(Attachment.builder().region("nova").build())
+            .createTime(dateService.iso8601SecondsDateParse("2012-04-10T10:39:52Z"))
+            .build());
+
+      assertEquals(client.describeVolumesInRegion("nova"), expected);
+   }
+
+}
diff --git a/apis/openstack-nova-ec2/src/test/resources/nova_ec2_availabilityZones.xml b/apis/openstack-nova-ec2/src/test/resources/nova_ec2_availabilityZones.xml
new file mode 100644
index 0000000..4ed5280
--- /dev/null
+++ b/apis/openstack-nova-ec2/src/test/resources/nova_ec2_availabilityZones.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" ?>
+<DescribeAvailabilityZonesResponse xmlns="http://ec2.amazonaws.com/doc/2009-04-04/">
+    <requestId>req-a6cd42f8-b5e5-4c94-a1e0-41d21ea0a032</requestId>
+    <availabilityZoneInfo>
+        <item>
+            <zoneState>available</zoneState>
+            <zoneName>nova</zoneName>
+        </item>
+    </availabilityZoneInfo>
+</DescribeAvailabilityZonesResponse>
\ No newline at end of file
diff --git a/apis/openstack-nova-ec2/src/test/resources/nova_ec2_describe_volumes.xml b/apis/openstack-nova-ec2/src/test/resources/nova_ec2_describe_volumes.xml
new file mode 100644
index 0000000..06b9e48
--- /dev/null
+++ b/apis/openstack-nova-ec2/src/test/resources/nova_ec2_describe_volumes.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" ?>
+<DescribeVolumesResponse xmlns="http://ec2.amazonaws.com/doc/2009-04-04/">
+    <requestId>req-9e45299b-980d-4893-a475-a574b1a94ed5</requestId>
+    <volumeSet>
+        <item>
+            <status>available (f06de98af01446b2ae6bd79f5fbf3b2a, att-openstack1, None, None)</status>
+            <availabilityZone>nova</availabilityZone>
+            <volumeId>vol-00000007</volumeId>
+            <attachmentSet>
+                <item/>
+            </attachmentSet>
+            <snapshotId/>
+            <createTime>2012-04-10T10:39:52.000Z</createTime>
+            <size>1</size>
+        </item>
+    </volumeSet>
+</DescribeVolumesResponse>
\ No newline at end of file
diff --git a/apis/openstack-nova-ec2/src/test/resources/nova_ec2_images_with_ramdisk.xml b/apis/openstack-nova-ec2/src/test/resources/nova_ec2_images_with_ramdisk.xml
new file mode 100644
index 0000000..b05df97
--- /dev/null
+++ b/apis/openstack-nova-ec2/src/test/resources/nova_ec2_images_with_ramdisk.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" ?>
+<DescribeImagesResponse xmlns="http://ec2.amazonaws.com/doc/2009-04-04/">
+    <requestId>req-bfdac708-c6c4-48fb-9cba-be5bb0a05b49</requestId>
+    <imagesSet>
+        <item>
+            <description/>
+            <imageOwnerId/>
+            <isPublic>true</isPublic>
+            <imageId>aki-00000002</imageId>
+            <imageState>available</imageState>
+            <architecture/>
+            <imageLocation>None (cirros-0.3.0-x86_64-blank-kernel)</imageLocation>
+            <rootDeviceType>instance-store</rootDeviceType>
+            <rootDeviceName>/dev/sda1</rootDeviceName>
+            <imageType>kernel</imageType>
+            <name>cirros-0.3.0-x86_64-blank-kernel</name>
+        </item>
+        <item>
+            <description/>
+            <imageOwnerId/>
+            <isPublic>true</isPublic>
+            <imageId>ari-00000003</imageId>
+            <imageState>available</imageState>
+            <architecture/>
+            <imageLocation>None (cirros-0.3.0-x86_64-blank-ramdisk)</imageLocation>
+            <rootDeviceType>instance-store</rootDeviceType>
+            <rootDeviceName>/dev/sda1</rootDeviceName>
+            <imageType>ramdisk</imageType>
+            <name>cirros-0.3.0-x86_64-blank-ramdisk</name>
+        </item>
+        <item>
+            <name>cirros-0.3.0-x86_64-blank</name>
+            <imageOwnerId/>
+            <isPublic>true</isPublic>
+            <imageId>ami-00000001</imageId>
+            <imageState>available</imageState>
+            <rootDeviceType>instance-store</rootDeviceType>
+            <architecture/>
+            <imageLocation>None (cirros-0.3.0-x86_64-blank)</imageLocation>
+            <kernelId>aki-00000002</kernelId>
+            <ramdiskId>ari-00000003</ramdiskId>
+            <rootDeviceName>/dev/sda1</rootDeviceName>
+            <imageType>machine</imageType>
+            <description/>
+        </item>
+    </imagesSet>
+</DescribeImagesResponse>
\ No newline at end of file
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/NovaComputeService.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/NovaComputeService.java
index bd79952..f957326 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/NovaComputeService.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/NovaComputeService.java
@@ -33,6 +33,7 @@
 import org.jclouds.Constants;
 import org.jclouds.collect.Memoized;
 import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.compute.ImageExtension;
 import org.jclouds.compute.callables.RunScriptOnNode;
 import org.jclouds.compute.domain.Hardware;
 import org.jclouds.compute.domain.Image;
@@ -103,12 +104,12 @@
          LoadingCache<ZoneAndName, SecurityGroupInZone> securityGroupMap,
          LoadingCache<ZoneAndName, KeyPair> keyPairCache,
          Function<Set<? extends NodeMetadata>, Multimap<String, String>> orphanedGroupsByZoneId,
-         GroupNamingConvention.Factory namingConvention) {
+         GroupNamingConvention.Factory namingConvention, Optional<ImageExtension> imageExtension) {
       super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
-            runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, stopNodeStrategy,
-            templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, nodeSuspended,
-            initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials, timeouts,
-            executor);
+               runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy,
+               stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
+               nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials,
+               timeouts, executor, imageExtension);
       this.novaClient = checkNotNull(novaClient, "novaClient");
       this.securityGroupMap = checkNotNull(securityGroupMap, "securityGroupMap");
       this.keyPairCache = checkNotNull(keyPairCache, "keyPairCache");
@@ -134,7 +135,7 @@
       if (securityGroupClient.isPresent()) {
          for (String group : groups) {
             for (SecurityGroup securityGroup : Iterables.filter(securityGroupClient.get().listSecurityGroups(),
-                  SecurityGroupPredicates.nameMatches(namingConvention.create().containsGroup(group)))) {
+                     SecurityGroupPredicates.nameMatches(namingConvention.create().containsGroup(group)))) {
                ZoneAndName zoneAndName = ZoneAndName.fromZoneAndName(zoneId, securityGroup.getName());
                logger.debug(">> deleting securityGroup(%s)", zoneAndName);
                securityGroupClient.get().deleteSecurityGroup(securityGroup.getId());
@@ -152,7 +153,7 @@
          for (String group : groups) {
             for (Map<String, KeyPair> wrapper : keyPairClient.get().listKeyPairs()) {
                for (KeyPair pair : Iterables.filter(wrapper.values(),
-                     KeyPairPredicates.nameMatches(namingConvention.create().containsGroup(group)))) {
+                        KeyPairPredicates.nameMatches(namingConvention.create().containsGroup(group)))) {
                   ZoneAndName zoneAndName = ZoneAndName.fromZoneAndName(zoneId, pair.getName());
                   logger.debug(">> deleting keypair(%s)", zoneAndName);
                   keyPairClient.get().deleteKeyPair(pair.getName());
@@ -162,7 +163,7 @@
                }
             }
             keyPairCache.invalidate(ZoneAndName.fromZoneAndName(zoneId,
-                  namingConvention.create().sharedNameForGroup(group)));
+                     namingConvention.create().sharedNameForGroup(group)));
          }
       }
    }
@@ -174,5 +175,7 @@
    public NovaTemplateOptions templateOptions() {
       return NovaTemplateOptions.class.cast(super.templateOptions());
    }
+   
+   
 
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/NovaImageExtension.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/NovaImageExtension.java
new file mode 100644
index 0000000..0b92881
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/NovaImageExtension.java
@@ -0,0 +1,101 @@
+/**
+ * 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.v1_1.compute;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.NoSuchElementException;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.compute.ImageExtension;
+import org.jclouds.compute.domain.CloneImageTemplate;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.ImageTemplate;
+import org.jclouds.compute.domain.ImageTemplateBuilder;
+import org.jclouds.openstack.nova.v1_1.NovaClient;
+import org.jclouds.openstack.nova.v1_1.domain.Server;
+import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ImageInZone;
+import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndId;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+
+@Singleton
+public class NovaImageExtension implements ImageExtension {
+   
+   private final NovaClient novaClient;
+   private final Function<ImageInZone, Image> imageInZoneToImage;
+
+   @Inject
+   public NovaImageExtension(NovaClient novaClient, Function<ImageInZone, Image> imageInZoneToImage) {
+      this.novaClient = checkNotNull(novaClient);
+      this.imageInZoneToImage = imageInZoneToImage;
+   }
+
+   @Override
+   public ImageTemplate buildImageTemplateFromNode(String name, final String id) {
+      ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(id);
+      Server server = novaClient.getServerClientForZone(zoneAndId.getZone()).getServer(zoneAndId.getId());
+      if (server == null)
+         throw new NoSuchElementException("Cannot find server with id: " + zoneAndId);
+      CloneImageTemplate template = new ImageTemplateBuilder.CloneImageTemplateBuilder().nodeId(id).name(name).build();
+      return template;
+   }
+
+   @Override
+   public Image createImage(ImageTemplate template) {
+      checkState(template instanceof CloneImageTemplate,
+               " openstack-nova only supports creating images through cloning.");
+      CloneImageTemplate cloneTemplate = (CloneImageTemplate) template;
+      ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(cloneTemplate.getSourceNodeId());
+      String newImageId = novaClient.getServerClientForZone(zoneAndId.getZone()).createImageFromServer(
+               cloneTemplate.getName(), zoneAndId.getId());
+      org.jclouds.openstack.nova.v1_1.domain.Image newImage = checkNotNull(findImage(ZoneAndId.fromZoneAndId(
+               zoneAndId.getZone(), newImageId)));
+      return imageInZoneToImage.apply(new ImageInZone(newImage, zoneAndId.getZone()));
+   }
+
+   @Override
+   public boolean deleteImage(String id) {
+      ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(id);
+      try {
+         this.novaClient.getImageClientForZone(zoneAndId.getZone()).deleteImage(zoneAndId.getId());
+      } catch (Exception e) {
+         return false;
+      }
+      return true;
+   }
+
+   private org.jclouds.openstack.nova.v1_1.domain.Image findImage(final ZoneAndId zoneAndId) {
+      return Iterables.tryFind(novaClient.getImageClientForZone(zoneAndId.getZone()).listImagesInDetail(),
+               new Predicate<org.jclouds.openstack.nova.v1_1.domain.Image>() {
+                  @Override
+                  public boolean apply(org.jclouds.openstack.nova.v1_1.domain.Image input) {
+                     return input.getId().equals(zoneAndId.getId());
+                  }
+               }).orNull();
+
+   }
+
+}
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/config/NovaComputeServiceContextModule.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/config/NovaComputeServiceContextModule.java
index 2351ac7..2ceaa9d 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/config/NovaComputeServiceContextModule.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/config/NovaComputeServiceContextModule.java
@@ -33,6 +33,7 @@
 import org.jclouds.collect.Memoized;
 import org.jclouds.compute.ComputeService;
 import org.jclouds.compute.ComputeServiceAdapter;
+import org.jclouds.compute.ImageExtension;
 import org.jclouds.compute.config.ComputeServiceAdapterContextModule;
 import org.jclouds.compute.domain.Hardware;
 import org.jclouds.compute.domain.Image;
@@ -46,6 +47,7 @@
 import org.jclouds.functions.IdentityFunction;
 import org.jclouds.openstack.nova.v1_1.compute.NovaComputeService;
 import org.jclouds.openstack.nova.v1_1.compute.NovaComputeServiceAdapter;
+import org.jclouds.openstack.nova.v1_1.compute.NovaImageExtension;
 import org.jclouds.openstack.nova.v1_1.compute.functions.CreateSecurityGroupIfNeeded;
 import org.jclouds.openstack.nova.v1_1.compute.functions.FlavorInZoneToHardware;
 import org.jclouds.openstack.nova.v1_1.compute.functions.ImageInZoneToImage;
@@ -69,6 +71,7 @@
 import org.jclouds.predicates.RetryablePredicate;
 
 import com.google.common.base.Function;
+import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;
 import com.google.common.base.Suppliers;
@@ -135,6 +138,9 @@
 
       bind(new TypeLiteral<CacheLoader<ZoneAndName, KeyPair>>() {
       }).to(CreateUniqueKeyPair.class);
+      
+      bind(new TypeLiteral<ImageExtension>() {
+      }).to(NovaImageExtension.class);
    }
 
    @Override
@@ -206,4 +212,9 @@
       }, locations);
 
    }
+   
+   @Override
+   protected Optional<ImageExtension> provideImageExtension(Injector i) {
+      return Optional.of(i.getInstance(ImageExtension.class));
+   }
 }
\ No newline at end of file
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/functions/ServerInZoneToNodeMetadata.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/functions/ServerInZoneToNodeMetadata.java
index 2157cf7..591574e 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/functions/ServerInZoneToNodeMetadata.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/functions/ServerInZoneToNodeMetadata.java
@@ -20,7 +20,6 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.collect.Iterables.concat;
 import static com.google.common.collect.Iterables.filter;
 import static com.google.common.collect.Iterables.find;
 import static com.google.common.collect.Iterables.transform;
@@ -51,9 +50,11 @@
 import org.jclouds.openstack.nova.v1_1.domain.Server;
 import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ServerInZone;
 import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndId;
+import org.jclouds.util.InetAddresses2;
 
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
 import com.google.common.base.Supplier;
 import com.google.common.net.InetAddresses;
 
@@ -103,14 +104,20 @@
       builder.hardware(findHardwareForServerOrNull(serverInZone));
       builder.state(from.getStatus().getNodeState());
       builder.publicAddresses(filter(
-            transform(concat(from.getPublicAddresses(), from.getInternetAddresses()),
+            transform(filter(from.getAddresses().values(), Predicates.not(isPrivateAddress)),
                   AddressToStringTransformationFunction.INSTANCE), isInet4Address));
       builder.privateAddresses(filter(
-            transform(from.getPrivateAddresses(), AddressToStringTransformationFunction.INSTANCE), isInet4Address));
+            transform(filter(from.getAddresses().values(), isPrivateAddress), AddressToStringTransformationFunction.INSTANCE), isInet4Address));
 
       return builder.build();
    }
-
+   
+   private static final Predicate<Address> isPrivateAddress = new Predicate<Address>() {
+      public boolean apply(Address in) {
+         return InetAddresses2.IsPrivateIPAddress.INSTANCE.apply(in.getAddr());
+      }
+   };
+   
    public static final Predicate<String> isInet4Address = new Predicate<String>() {
       @Override
       public boolean apply(String input) {
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Address.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Address.java
index 3053ccf..7faa0b4 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Address.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Address.java
@@ -30,42 +30,7 @@
  * @author AdrianCole
  */
 public class Address {
-
-   /**
-    * Relations associated with resources.
-    */
-   public static enum Type {
-      /**
-       * internet routable address
-       */
-      INTERNET,
-      /**
-       * publically routable address
-       */
-      PUBLIC,
-      /**
-       * address that is not publicly routable.
-       */
-      PRIVATE,
-      /**
-       * the value returned by the OpenStack service was not recognized.
-       */
-      UNRECOGNIZED;
-
-      public String value() {
-         return name().toLowerCase();
-      }
-
-      public static Type fromValue(String v) {
-         try {
-            return valueOf(v.toUpperCase());
-         } catch (IllegalArgumentException e) {
-            return UNRECOGNIZED;
-         }
-      }
-
-   }
-
+  
    public static Builder builder() {
       return new Builder();
    }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Server.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Server.java
index 9850663..576d2a3 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Server.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Server.java
@@ -20,7 +20,6 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import java.util.Collection;
 import java.util.Date;
 import java.util.Map;
 import java.util.Set;
@@ -29,20 +28,14 @@
 import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.openstack.domain.Link;
 import org.jclouds.openstack.domain.Resource;
-import org.jclouds.openstack.nova.v1_1.domain.Address.Type;
 import org.jclouds.openstack.nova.v1_1.extensions.KeyPairClient;
-import org.jclouds.util.InetAddresses2;
 import org.jclouds.util.Multimaps2;
 
-import com.google.common.base.Predicate;
+import com.google.common.base.Objects.ToStringHelper;
 import com.google.common.base.Predicates;
 import com.google.common.base.Strings;
-import com.google.common.base.Objects.ToStringHelper;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableMultimap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSetMultimap;
-import com.google.common.collect.Iterables;
 import com.google.common.collect.LinkedHashMultimap;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
@@ -122,7 +115,7 @@
       private Resource flavor;
       private Map<String, String> metadata = Maps.newHashMap();
       // TODO: get gson multimap ad
-      private Multimap<Address.Type, Address> addresses = LinkedHashMultimap.create();
+      private Multimap<String, Address> addresses = LinkedHashMultimap.create();
       private String adminPass;
       private String keyName;
 
@@ -233,60 +226,12 @@
       /**
        * @see Server#getAddresses()
        */
-      public Builder addresses(Multimap<Address.Type, Address> addresses) {
+      public Builder addresses(Multimap<String, Address> addresses) {
          this.addresses = ImmutableMultimap.copyOf(checkNotNull(addresses, "addresses"));
          return this;
       }
-
-      /**
-       * @see Server#getPrivateAddresses()
-       */
-      public Builder privateAddresses(Address... privateAddresses) {
-         return privateAddresses(ImmutableSet.copyOf(checkNotNull(privateAddresses, "privateAddresses")));
-      }
-
-      /**
-       * @see Server#getPrivateAddresses()
-       */
-      public Builder privateAddresses(Set<Address> privateAddresses) {
-         this.addresses.replaceValues(Address.Type.PRIVATE, ImmutableSet.copyOf(checkNotNull(privateAddresses,
-                  "privateAddresses")));
-         return this;
-      }
       
       /**
-       * @see Server#getInternetAddresses()
-       */
-      public Builder internetAddresses(Address... internetAddresses) {
-         return internetAddresses(ImmutableSet.copyOf(checkNotNull(internetAddresses, "internetAddresses")));
-      }
-
-      /**
-       * @see Server#getInternetAddresses()
-       */
-      public Builder internetAddresses(Set<Address> internetAddresses) {
-         this.addresses.replaceValues(Address.Type.INTERNET, ImmutableSet.copyOf(checkNotNull(internetAddresses,
-                  "internetAddresses")));
-         return this;
-      }
-      
-      /**
-       * @see Server#getPublicAddresses()
-       */
-      public Builder publicAddresses(Address... publicAddresses) {
-         return publicAddresses(ImmutableSet.copyOf(checkNotNull(publicAddresses, "publicAddresses")));
-      }
-
-      /**
-       * @see Server#getPublicAddresses()
-       */
-      public Builder publicAddresses(Set<Address> publicAddresses) {
-         this.addresses.replaceValues(Address.Type.PUBLIC, ImmutableSet.copyOf(checkNotNull(publicAddresses,
-                  "publicAddresses")));
-         return this;
-      }
-
-      /**
        * @see Server#getAdminPass()
        */
       public Builder adminPass(String adminPass) {
@@ -376,13 +321,13 @@
    @SerializedName("config_drive")
    protected final String configDrive;
    // TODO: get gson multimap adapter!
-   protected final Map<Address.Type, Set<Address>> addresses;
+   protected final Map<String, Set<Address>> addresses;
    protected final Map<String, String> metadata;
 
    protected Server(String id, String name, Set<Link> links, @Nullable String uuid, String tenantId, String userId,
             Date updated, Date created, @Nullable String hostId, @Nullable String accessIPv4,
             @Nullable String accessIPv6, Status status, @Nullable String configDrive, Resource image, Resource flavor,
-            String adminPass, @Nullable String keyName, Multimap<Address.Type, Address> addresses,
+            String adminPass, @Nullable String keyName, Multimap<String, Address> addresses,
             Map<String, String> metadata) {
       super(id, name, links);
       this.uuid = uuid; // TODO: see what version this came up in
@@ -471,74 +416,10 @@
    }
 
    /**
-    * @return the private ip addresses assigned to the server
-    */
-   public Set<Address> getPrivateAddresses() {
-      Collection<Address> privateAddresses = getAddresses().get(Address.Type.PRIVATE);
-      if (privateAddresses == null) {
-         return ImmutableSet.<Address> of();
-      } else {
-         return ImmutableSet.copyOf(privateAddresses);
-      }
-   }
-   
-   /**
-    * @return the internet ip addresses assigned to the server
-    * @since essex
-    */
-   public Set<Address> getInternetAddresses() {
-      Collection<Address> internetAddrs = getAddresses().get(Address.Type.INTERNET);
-      if (internetAddrs == null) {
-         return ImmutableSet.<Address> of();
-      } else {
-         return ImmutableSet.copyOf(internetAddrs);
-      }
-   }
-
-   /**
-    * @return the public ip addresses assigned to the server
-    */
-   public Set<Address> getPublicAddresses() {
-      Collection<Address> publicAddrs = getAddresses().get(Address.Type.PUBLIC);
-      if (publicAddrs == null) {
-         return ImmutableSet.<Address> of();
-      } else {
-         return ImmutableSet.copyOf(publicAddrs);
-      }
-   }
-
-   /**
     * @return the ip addresses assigned to the server
     */
-   public Multimap<Type, Address> getAddresses() {
-
-      Set<Address> privateAddresses = addresses.get(Address.Type.PRIVATE);
-
-      if (privateAddresses != null && privateAddresses.size() > 1) {
-         return hackNeededForFloatingIpsFixedInEssex(privateAddresses);
-      } else {
-         return Multimaps2.fromOldSchool(addresses);
-      }
-
-   }
-
-   private Multimap<Type, Address> hackNeededForFloatingIpsFixedInEssex(Set<Address> privateAddresses) {
-      Set<Address> publicAddresses = addresses.get(Address.Type.PUBLIC);
-      ImmutableSetMultimap.Builder<Type, Address> returnMapBuilder = new ImmutableSetMultimap.Builder<Type, Address>();
-      if (publicAddresses != null) {
-         returnMapBuilder.putAll(Address.Type.PUBLIC, publicAddresses);
-      }
-      returnMapBuilder.putAll(Address.Type.PRIVATE, Iterables.filter(privateAddresses, IsPrivateAddress.INSTANCE));
-      returnMapBuilder.putAll(Address.Type.PUBLIC, Iterables.filter(privateAddresses, Predicates
-               .not(IsPrivateAddress.INSTANCE)));
-      return returnMapBuilder.build();
-   }
-
-   private static enum IsPrivateAddress implements Predicate<Address> {
-      INSTANCE;
-      public boolean apply(Address in) {
-         return InetAddresses2.IsPrivateIPAddress.INSTANCE.apply(in.getAddr());
-      }
+   public Multimap<String, Address> getAddresses() {
+      return Multimaps2.fromOldSchool(addresses);
    }
 
    /**
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/extensions/FloatingIPClientLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/extensions/FloatingIPClientLiveTest.java
index 1db2604..b3262d3 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/extensions/FloatingIPClientLiveTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/extensions/FloatingIPClientLiveTest.java
@@ -181,7 +181,7 @@
          try {
             Server server = client.getServer(serverId);
             boolean ipInServerAddresses = false;
-            Multimap<Address.Type, Address> addresses = server.getAddresses();
+            Multimap<String, Address> addresses = server.getAddresses();
             for (Address address : addresses.values()) {
                if (address.getAddr().equals(floatingIP)) {
                   ipInServerAddresses = true;
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/internal/BaseNovaComputeServiceContextExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/internal/BaseNovaComputeServiceContextExpectTest.java
index f7e3681..9105e3a 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/internal/BaseNovaComputeServiceContextExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/internal/BaseNovaComputeServiceContextExpectTest.java
@@ -18,22 +18,17 @@
  */
 package org.jclouds.openstack.nova.v1_1.internal;
 
-import java.io.InputStream;
 import java.net.URI;
 import java.util.Properties;
-import java.util.concurrent.ConcurrentHashMap;
 
 import org.jclouds.apis.ApiMetadata;
 import org.jclouds.compute.ComputeServiceContext;
 import org.jclouds.http.HttpRequest;
 import org.jclouds.http.HttpResponse;
-import org.jclouds.io.CopyInputStreamInputSupplierMap;
 import org.jclouds.openstack.nova.v1_1.NovaApiMetadata;
-import org.jclouds.rest.config.CredentialStoreModule;
 
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableMultimap;
-import com.google.common.io.InputSupplier;
 import com.google.inject.Module;
 
 /**
@@ -91,12 +86,4 @@
       return new NovaApiMetadata();
    }
 
-   // isolate tests from eachother, as default credentialStore is static
-   protected Module credentialStoreModule = new CredentialStoreModule(new CopyInputStreamInputSupplierMap(
-         new ConcurrentHashMap<String, InputSupplier<InputStream>>()));
-
-   @Override
-   protected Module createModule() {
-      return credentialStoreModule;
-   }
 }
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerDetailsEssexTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerDetailsEssexTest.java
new file mode 100644
index 0000000..a4e7f51
--- /dev/null
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerDetailsEssexTest.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.openstack.nova.v1_1.parse;
+
+import java.net.URI;
+import java.util.Set;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.date.internal.SimpleDateFormatDateService;
+import org.jclouds.json.BaseSetParserTest;
+import org.jclouds.json.config.GsonModule;
+import org.jclouds.openstack.domain.Link;
+import org.jclouds.openstack.domain.Link.Relation;
+import org.jclouds.openstack.domain.Resource;
+import org.jclouds.openstack.nova.v1_1.config.NovaParserModule;
+import org.jclouds.openstack.nova.v1_1.domain.Address;
+import org.jclouds.openstack.nova.v1_1.domain.Server;
+import org.jclouds.rest.annotations.SelectJson;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+
+/**
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "ParseServerDetailsEssexTest")
+public class ParseServerDetailsEssexTest extends BaseSetParserTest<Server> {
+
+   @Override
+   public String resource() {
+      return "/server_list_details_essex.json";
+   }
+
+   @Override
+   @SelectJson("servers")
+   @Consumes(MediaType.APPLICATION_JSON)
+   public Set<Server> expected() {
+      return ImmutableSet.<Server>of(
+            Server.builder()
+                  .addresses(ImmutableMultimap.<String, Address>builder()
+                     .putAll("Net TenantA Front-Middle", Address.createV4("172.16.11.5"))
+                     .putAll("Public network", Address.createV4("172.16.1.13"), Address.createV4("10.193.112.119")).build())
+                  .links(
+                     Link.create(
+                        Relation.SELF,
+                        URI.create("http://nova:8774/v1.1/8d10e6646d5d4585937395b04839a353/servers/0c80b392-db30-4736-ae02-4480090f1207")),
+                     Link.create(
+                        Relation.BOOKMARK,
+                        URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/servers/0c80b392-db30-4736-ae02-4480090f1207")))
+                  .image(
+                     Resource.builder()
+                        .id("416af940-2d3c-4a7c-977c-a9030685ad5e")
+                        .links(
+                           Link.create(
+                              Relation.BOOKMARK,
+                              URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/images/416af940-2d3c-4a7c-977c-a9030685ad5e"))).build())
+                  .flavor(
+                     Resource.builder()
+                        .id("1")
+                        .links(
+                           Link.create(
+                              Relation.BOOKMARK,
+                              URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/flavors/1"))).build())
+                  .id("0c80b392-db30-4736-ae02-4480090f1207")
+                  .userId("df13814f6c354d00a8acf66502836323")
+                  .status(Server.Status.ACTIVE)
+                  .updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:21:33Z"))
+                  .hostId("03d796ebb52b1b555e5f6d9262f7dbd52b3f7c181e3aa89b34ca5408")
+                  .name("VM proxy")
+                  .created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:21:23Z"))
+                  .tenantId("8d10e6646d5d4585937395b04839a353").build(),
+            Server.builder()
+                  .addresses(ImmutableMultimap.<String, Address>builder()
+                    .putAll("Net TenantA Front-Middle", Address.createV4("172.16.11.4"))
+                    .putAll("Net TenantA Middle-Back", Address.createV4("172.16.12.5")).build())
+                  .links(
+                     Link.create(
+                        Relation.SELF,
+                        URI.create("http://nova:8774/v1.1/8d10e6646d5d4585937395b04839a353/servers/b332b5cd-535e-4677-b68e-fc8badc13236")),
+                     Link.create(
+                        Relation.BOOKMARK,
+                        URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/servers/b332b5cd-535e-4677-b68e-fc8badc13236")))
+                  .image(
+                     Resource.builder()
+                        .id("416af940-2d3c-4a7c-977c-a9030685ad5e")
+                        .links(
+                           Link.create(
+                              Relation.BOOKMARK,
+                              URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/images/416af940-2d3c-4a7c-977c-a9030685ad5e"))).build())
+                  .flavor(
+                     Resource.builder()
+                        .id("1")
+                        .links(
+                           Link.create(
+                              Relation.BOOKMARK,
+                              URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/flavors/1"))).build())
+                  .id("b332b5cd-535e-4677-b68e-fc8badc13236")
+                  .userId("df13814f6c354d00a8acf66502836323")
+                  .status(Server.Status.ACTIVE)
+                  .updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:18:58Z"))
+                  .hostId("e5bbff80bebacfe1db63951e787b5341427060a602d33abfefb6a1bc")
+                  .name("VM blog")
+                  .created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:18:48Z"))
+                  .tenantId("8d10e6646d5d4585937395b04839a353").build(),
+               Server.builder()
+                  .addresses(ImmutableMultimap.<String, Address>builder()
+                    .putAll("Net TenantA Middle-Back", Address.createV4("172.16.12.4")).build())
+                  .links(
+                     Link.create(
+                        Relation.SELF,
+                        URI.create("http://nova:8774/v1.1/8d10e6646d5d4585937395b04839a353/servers/f9d43436-4572-4c9b-9b74-5fa6890a2f21")),
+                     Link.create(
+                        Relation.BOOKMARK,
+                        URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/servers/f9d43436-4572-4c9b-9b74-5fa6890a2f21")))
+                  .image(
+                     Resource.builder()
+                        .id("416af940-2d3c-4a7c-977c-a9030685ad5e")
+                        .links(
+                           Link.create(
+                              Relation.BOOKMARK,
+                              URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/images/416af940-2d3c-4a7c-977c-a9030685ad5e"))).build())
+                  .flavor(
+                     Resource.builder()
+                        .id("1")
+                        .links(
+                           Link.create(
+                              Relation.BOOKMARK,
+                              URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/flavors/1"))).build())
+                  .id("f9d43436-4572-4c9b-9b74-5fa6890a2f21")
+                  .userId("df13814f6c354d00a8acf66502836323")
+                  .status(Server.Status.ACTIVE)
+                  .updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:15:09Z"))
+                  .hostId("03d796ebb52b1b555e5f6d9262f7dbd52b3f7c181e3aa89b34ca5408")
+                  .name("VM MySQL")
+                  .created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:14:56Z"))
+                  .tenantId("8d10e6646d5d4585937395b04839a353").build());
+   }
+  
+
+   protected Injector injector() {
+      return Guice.createInjector(new NovaParserModule(), new GsonModule());
+   }
+}
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerTest.java
index f249f3b..7e54bd0 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerTest.java
@@ -37,6 +37,7 @@
 import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMultimap;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
@@ -96,9 +97,11 @@
             .metadata(
                   new ImmutableMap.Builder<String, String>().put("Server Label", "Web Head 1")
                         .put("Image Version", "2.1").build())
-            .publicAddresses(Address.createV4("67.23.10.132"), Address.createV6("::babe:67.23.10.132"),
+            .addresses(ImmutableMultimap.<String, Address>builder()
+                  .putAll("public", Address.createV4("67.23.10.132"), Address.createV6("::babe:67.23.10.132"),
                   Address.createV4("67.23.10.131"), Address.createV6("::babe:4317:0A83"))
-            .privateAddresses(Address.createV4("10.176.42.16"), Address.createV6("::babe:10.176.42.16")).build();
+                  .putAll("private", Address.createV4("10.176.42.16"), Address.createV6("::babe:10.176.42.16"))
+                  .build()).build();
 
    }
 
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerWithInternetAddressesTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerWithInternetAddressesTest.java
index b5272f2..15a0dae 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerWithInternetAddressesTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerWithInternetAddressesTest.java
@@ -36,6 +36,7 @@
 import org.jclouds.rest.annotations.SelectJson;
 import org.testng.annotations.Test;
 
+import com.google.common.collect.ImmutableMultimap;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
@@ -90,7 +91,7 @@
                   Link.create(
                          Relation.BOOKMARK,
                          URI.create("https://nova-api.trystack.org:9774/37/servers/1459")))
-            .internetAddresses(Address.createV4("8.21.28.47")).build();
+            .addresses(ImmutableMultimap.of("internet", Address.createV4("8.21.28.47"))).build();
    }
   
 
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/PublicIpsInPrivateAddressBlockShouldRerouteToPublicBlockExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/PublicIpsInPrivateAddressBlockExpectTest.java
similarity index 92%
rename from apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/PublicIpsInPrivateAddressBlockShouldRerouteToPublicBlockExpectTest.java
rename to apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/PublicIpsInPrivateAddressBlockExpectTest.java
index 7df750e..1d25130 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/PublicIpsInPrivateAddressBlockShouldRerouteToPublicBlockExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/PublicIpsInPrivateAddressBlockExpectTest.java
@@ -37,6 +37,7 @@
 import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMultimap;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
@@ -44,7 +45,7 @@
  * @author Adrian Cole
  */
 @Test(groups = "unit", testName = "ParseCreatedServerTest")
-public class PublicIpsInPrivateAddressBlockShouldRerouteToPublicBlockExpectTest extends BaseItemParserTest<Server> {
+public class PublicIpsInPrivateAddressBlockExpectTest extends BaseItemParserTest<Server> {
 
    @Override
    public String resource() {
@@ -86,8 +87,8 @@
                                     URI.create("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/flavors/100")))
                         .build())
             .metadata(ImmutableMap.of("Name", "hpcloud-computes"))
-            .privateAddresses(Address.createV4("10.6.39.189"))
-            .publicAddresses(Address.createV4("15.185.181.94"))
+            .addresses(ImmutableMultimap.<String, Address>builder()
+                  .putAll("private", Address.createV4("10.6.39.189"), Address.createV4("15.185.181.94")).build())
             .links(
                      Link.create(Relation.SELF, URI.create("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/v1.1/37936628937291/servers/59662")),
                      Link.create(Relation.BOOKMARK, URI.create("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/servers/59662"))).build();
diff --git a/apis/openstack-nova/src/test/resources/server_list_details_essex.json b/apis/openstack-nova/src/test/resources/server_list_details_essex.json
new file mode 100644
index 0000000..9ca9445
--- /dev/null
+++ b/apis/openstack-nova/src/test/resources/server_list_details_essex.json
@@ -0,0 +1,152 @@
+{
+    "servers": [{
+        "OS-EXT-STS:task_state": null,
+        "addresses": {
+            "Net TenantA Front-Middle": [{
+                "version": 4,
+                "addr": "172.16.11.5"
+            }],
+            "Public network": [{
+                "version": 4,
+                "addr": "172.16.1.13"
+            }, {
+                "version": 4,
+                "addr": "10.193.112.119"
+            }]
+        },
+        "links": [{
+            "href": "http://nova:8774/v1.1/8d10e6646d5d4585937395b04839a353/servers/0c80b392-db30-4736-ae02-4480090f1207",
+            "rel": "self"
+        }, {
+            "href": "http://nova:8774/8d10e6646d5d4585937395b04839a353/servers/0c80b392-db30-4736-ae02-4480090f1207",
+            "rel": "bookmark"
+        }],
+        "image": {
+            "id": "416af940-2d3c-4a7c-977c-a9030685ad5e",
+            "links": [{
+                "href": "http://nova:8774/8d10e6646d5d4585937395b04839a353/images/416af940-2d3c-4a7c-977c-a9030685ad5e",
+                "rel": "bookmark"
+            }]
+        },
+        "OS-EXT-STS:vm_state": "active",
+        "flavor": {
+            "id": "1",
+            "links": [{
+                "href": "http://nova:8774/8d10e6646d5d4585937395b04839a353/flavors/1",
+                "rel": "bookmark"
+            }]
+        },
+        "id": "0c80b392-db30-4736-ae02-4480090f1207",
+        "user_id": "df13814f6c354d00a8acf66502836323",
+        "OS-DCF:diskConfig": "MANUAL",
+        "accessIPv4": "",
+        "accessIPv6": "",
+        "progress": 0,
+        "OS-EXT-STS:power_state": 1,
+        "config_drive": "",
+        "status": "ACTIVE",
+        "updated": "2012-04-12T11:21:33Z",
+        "hostId": "03d796ebb52b1b555e5f6d9262f7dbd52b3f7c181e3aa89b34ca5408",
+        "key_name": "",
+        "name": "VM proxy",
+        "created": "2012-04-12T11:21:23Z",
+        "tenant_id": "8d10e6646d5d4585937395b04839a353",
+        "metadata": {}
+    }, {
+        "OS-EXT-STS:task_state": null,
+        "addresses": {
+            "Net TenantA Front-Middle": [{
+                "version": 4,
+                "addr": "172.16.11.4"
+            }],
+            "Net TenantA Middle-Back": [{
+                "version": 4,
+                "addr": "172.16.12.5"
+            }]
+        },
+        "links": [{
+            "href": "http://nova:8774/v1.1/8d10e6646d5d4585937395b04839a353/servers/b332b5cd-535e-4677-b68e-fc8badc13236",
+            "rel": "self"
+        }, {
+            "href": "http://nova:8774/8d10e6646d5d4585937395b04839a353/servers/b332b5cd-535e-4677-b68e-fc8badc13236",
+            "rel": "bookmark"
+        }],
+        "image": {
+            "id": "416af940-2d3c-4a7c-977c-a9030685ad5e",
+            "links": [{
+                "href": "http://nova:8774/8d10e6646d5d4585937395b04839a353/images/416af940-2d3c-4a7c-977c-a9030685ad5e",
+                "rel": "bookmark"
+            }]
+        },
+        "OS-EXT-STS:vm_state": "active",
+        "flavor": {
+            "id": "1",
+            "links": [{
+                "href": "http://nova:8774/8d10e6646d5d4585937395b04839a353/flavors/1",
+                "rel": "bookmark"
+            }]
+        },
+        "id": "b332b5cd-535e-4677-b68e-fc8badc13236",
+        "user_id": "df13814f6c354d00a8acf66502836323",
+        "OS-DCF:diskConfig": "MANUAL",
+        "accessIPv4": "",
+        "accessIPv6": "",
+        "progress": 0,
+        "OS-EXT-STS:power_state": 1,
+        "config_drive": "",
+        "status": "ACTIVE",
+        "updated": "2012-04-12T11:18:58Z",
+        "hostId": "e5bbff80bebacfe1db63951e787b5341427060a602d33abfefb6a1bc",
+        "key_name": "",
+        "name": "VM blog",
+        "created": "2012-04-12T11:18:48Z",
+        "tenant_id": "8d10e6646d5d4585937395b04839a353",
+        "metadata": {}
+    }, {
+        "OS-EXT-STS:task_state": null,
+        "addresses": {
+            "Net TenantA Middle-Back": [{
+                "version": 4,
+                "addr": "172.16.12.4"
+            }]
+        },
+        "links": [{
+            "href": "http://nova:8774/v1.1/8d10e6646d5d4585937395b04839a353/servers/f9d43436-4572-4c9b-9b74-5fa6890a2f21",
+            "rel": "self"
+        }, {
+            "href": "http://nova:8774/8d10e6646d5d4585937395b04839a353/servers/f9d43436-4572-4c9b-9b74-5fa6890a2f21",
+            "rel": "bookmark"
+        }],
+        "image": {
+            "id": "416af940-2d3c-4a7c-977c-a9030685ad5e",
+            "links": [{
+                "href": "http://nova:8774/8d10e6646d5d4585937395b04839a353/images/416af940-2d3c-4a7c-977c-a9030685ad5e",
+                "rel": "bookmark"
+            }]
+        },
+        "OS-EXT-STS:vm_state": "active",
+        "flavor": {
+            "id": "1",
+            "links": [{
+                "href": "http://nova:8774/8d10e6646d5d4585937395b04839a353/flavors/1",
+                "rel": "bookmark"
+            }]
+        },
+        "id": "f9d43436-4572-4c9b-9b74-5fa6890a2f21",
+        "user_id": "df13814f6c354d00a8acf66502836323",
+        "OS-DCF:diskConfig": "MANUAL",
+        "accessIPv4": "",
+        "accessIPv6": "",
+        "progress": 0,
+        "OS-EXT-STS:power_state": 1,
+        "config_drive": "",
+        "status": "ACTIVE",
+        "updated": "2012-04-12T11:15:09Z",
+        "hostId": "03d796ebb52b1b555e5f6d9262f7dbd52b3f7c181e3aa89b34ca5408",
+        "key_name": "",
+        "name": "VM MySQL",
+        "created": "2012-04-12T11:14:56Z",
+        "tenant_id": "8d10e6646d5d4585937395b04839a353",
+        "metadata": {}
+    }]
+}
\ No newline at end of file
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 486df9b..a7131c8 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
@@ -27,12 +27,12 @@
 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.rest.config.BinderUtils.bindClientAndAsyncClient;
 import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_FENCEMODE;
 import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_TIMEOUT_TASK_COMPLETED;
+import static org.jclouds.util.Maps2.uniqueIndex;
 
 import java.net.URI;
 import java.util.Map;
@@ -118,6 +118,7 @@
 import com.google.common.cache.LoadingCache;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableMap.Builder;
+import com.google.common.collect.Lists;
 import com.google.inject.Injector;
 import com.google.inject.Provides;
 import com.google.inject.Scopes;
@@ -285,26 +286,27 @@
 
    @Singleton
    public static class OrgCatalogSupplier implements
-            Supplier<Map<String, Map<String, org.jclouds.vcloud.domain.Catalog>>> {
+            Supplier<Map<String, Map<String, Catalog>>> {
       protected final Supplier<Map<String, Org>> orgSupplier;
-      protected final Function<Org, Iterable<org.jclouds.vcloud.domain.Catalog>> allCatalogsInOrg;
+      protected final Function<Org, Iterable<Catalog>> allCatalogsInOrg;
 
       @Inject
       protected OrgCatalogSupplier(Supplier<Map<String, Org>> orgSupplier,
-               Function<Org, Iterable<org.jclouds.vcloud.domain.Catalog>> allCatalogsInOrg) {
+               Function<Org, Iterable<Catalog>> allCatalogsInOrg) {
          this.orgSupplier = orgSupplier;
          this.allCatalogsInOrg = allCatalogsInOrg;
       }
 
       @Override
-      public Map<String, Map<String, org.jclouds.vcloud.domain.Catalog>> get() {
+      public Map<String, Map<String, Catalog>> get() {
          return transformValues(
                   transformValues(orgSupplier.get(), allCatalogsInOrg),
-                  new Function<Iterable<org.jclouds.vcloud.domain.Catalog>, Map<String, org.jclouds.vcloud.domain.Catalog>>() {
+                  new Function<Iterable<? extends Catalog>, 
+                  Map<String, Catalog>>() {
 
                      @Override
-                     public Map<String, org.jclouds.vcloud.domain.Catalog> apply(
-                              Iterable<org.jclouds.vcloud.domain.Catalog> from) {
+                     public Map<String, Catalog> apply(
+                              Iterable<? extends Catalog> from) {
                         return uniqueIndex(from, name);
                      }
 
@@ -336,37 +338,37 @@
 
    @Provides
    @Singleton
-   protected Supplier<Map<URI, org.jclouds.vcloud.domain.VDC>> provideURIToVDC(
+   protected Supplier<Map<URI, VDC>> provideURIToVDC(
             @Named(PROPERTY_SESSION_INTERVAL) long seconds, AtomicReference<AuthorizationException> authException,
             URItoVDC supplier) {
-      return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<URI, org.jclouds.vcloud.domain.VDC>>(
+      return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<URI, VDC>>(
                authException, seconds, supplier);
    }
 
    @Singleton
-   public static class URItoVDC implements Supplier<Map<URI, org.jclouds.vcloud.domain.VDC>> {
-      private final Supplier<Map<String, Map<String, org.jclouds.vcloud.domain.VDC>>> orgVDCMap;
+   public static class URItoVDC implements Supplier<Map<URI, VDC>> {
+      private final Supplier<Map<String, Map<String, VDC>>> orgVDCMap;
 
       @Inject
-      URItoVDC(Supplier<Map<String, Map<String, org.jclouds.vcloud.domain.VDC>>> orgVDCMap) {
+      URItoVDC(Supplier<Map<String, Map<String, VDC>>> orgVDCMap) {
          this.orgVDCMap = orgVDCMap;
       }
 
       @Override
-      public Map<URI, org.jclouds.vcloud.domain.VDC> get() {
+      public Map<URI, VDC> get() {
          return uniqueIndex(concat(transform(orgVDCMap.get().values(),
-                  new Function<Map<String, org.jclouds.vcloud.domain.VDC>, Iterable<org.jclouds.vcloud.domain.VDC>>() {
+                  new Function<Map<String, VDC>, Iterable<VDC>>() {
 
                      @Override
-                     public Iterable<org.jclouds.vcloud.domain.VDC> apply(
-                              Map<String, org.jclouds.vcloud.domain.VDC> from) {
+                     public Iterable<VDC> apply(
+                              Map<String, VDC> from) {
                         return from.values();
                      }
 
-                  })), new Function<org.jclouds.vcloud.domain.VDC, URI>() {
+                  })), new Function<VDC, URI>() {
 
             @Override
-            public URI apply(org.jclouds.vcloud.domain.VDC from) {
+            public URI apply(VDC from) {
                return from.getHref();
             }
 
@@ -445,43 +447,43 @@
 
    @Provides
    @Singleton
-   protected Supplier<Map<String, Map<String, org.jclouds.vcloud.domain.Catalog>>> provideOrgCatalogItemMapSupplierCache(
+   protected Supplier<Map<String, Map<String, Catalog>>> provideOrgCatalogItemMapSupplierCache(
             @Named(PROPERTY_SESSION_INTERVAL) long seconds, AtomicReference<AuthorizationException> authException,
             OrgCatalogSupplier supplier) {
-      return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<String, Map<String, org.jclouds.vcloud.domain.Catalog>>>(
+      return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<String, Map<String, Catalog>>>(
                authException, seconds, supplier);
    }
 
    @Provides
    @Singleton
-   protected Supplier<Map<String, Map<String, org.jclouds.vcloud.domain.VDC>>> provideOrgVDCSupplierCache(
+   protected Supplier<Map<String, Map<String, VDC>>> provideOrgVDCSupplierCache(
             @Named(PROPERTY_SESSION_INTERVAL) long seconds, AtomicReference<AuthorizationException> authException,
             OrgVDCSupplier supplier) {
-      return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<String, Map<String, org.jclouds.vcloud.domain.VDC>>>(
+      return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<String, Map<String, VDC>>>(
                authException, seconds, supplier);
    }
 
    @Singleton
-   public static class OrgVDCSupplier implements Supplier<Map<String, Map<String, org.jclouds.vcloud.domain.VDC>>> {
+   public static class OrgVDCSupplier implements Supplier<Map<String, Map<String, VDC>>> {
       protected final Supplier<Map<String, Org>> orgSupplier;
-      private final Function<Org, Iterable<org.jclouds.vcloud.domain.VDC>> allVDCsInOrg;
+      private final Function<Org, Iterable<VDC>> allVDCsInOrg;
 
       @Inject
       protected OrgVDCSupplier(Supplier<Map<String, Org>> orgSupplier,
-               Function<Org, Iterable<org.jclouds.vcloud.domain.VDC>> allVDCsInOrg) {
+               Function<Org, Iterable<VDC>> allVDCsInOrg) {
          this.orgSupplier = orgSupplier;
          this.allVDCsInOrg = allVDCsInOrg;
       }
 
       @Override
-      public Map<String, Map<String, org.jclouds.vcloud.domain.VDC>> get() {
+      public Map<String, Map<String, VDC>> get() {
          return transformValues(transformValues(orgSupplier.get(), allVDCsInOrg),
-                  new Function<Iterable<org.jclouds.vcloud.domain.VDC>, Map<String, org.jclouds.vcloud.domain.VDC>>() {
+                  new Function<Iterable<? extends VDC>, Map<String, VDC>>() {
 
                      @Override
-                     public Map<String, org.jclouds.vcloud.domain.VDC> apply(
-                              Iterable<org.jclouds.vcloud.domain.VDC> from) {
-                        return uniqueIndex(from, name);
+                     public Map<String, VDC> apply(
+                              Iterable<? extends VDC> from) {
+                        return uniqueIndex(Lists.newArrayList(from), name);
                      }
 
                   });
@@ -490,33 +492,33 @@
 
    @Singleton
    public static class OrgCatalogItemSupplier implements
-            Supplier<Map<String, Map<String, Map<String, org.jclouds.vcloud.domain.CatalogItem>>>> {
-      protected final Supplier<Map<String, Map<String, org.jclouds.vcloud.domain.Catalog>>> catalogSupplier;
-      protected final Function<org.jclouds.vcloud.domain.Catalog, Iterable<CatalogItem>> allCatalogItemsInCatalog;
+            Supplier<Map<String, Map<String, Map<String, CatalogItem>>>> {
+      protected final Supplier<Map<String, Map<String, Catalog>>> catalogSupplier;
+      protected final Function<Catalog, Iterable<CatalogItem>> allCatalogItemsInCatalog;
 
       @Inject
       protected OrgCatalogItemSupplier(
-               Supplier<Map<String, Map<String, org.jclouds.vcloud.domain.Catalog>>> catalogSupplier,
-               Function<org.jclouds.vcloud.domain.Catalog, Iterable<CatalogItem>> allCatalogItemsInCatalog) {
+               Supplier<Map<String, Map<String, Catalog>>> catalogSupplier,
+               Function<Catalog, Iterable<CatalogItem>> allCatalogItemsInCatalog) {
          this.catalogSupplier = catalogSupplier;
          this.allCatalogItemsInCatalog = allCatalogItemsInCatalog;
       }
 
       @Override
-      public Map<String, Map<String, Map<String, org.jclouds.vcloud.domain.CatalogItem>>> get() {
+      public Map<String, Map<String, Map<String, CatalogItem>>> get() {
          return transformValues(
                   catalogSupplier.get(),
-                  new Function<Map<String, org.jclouds.vcloud.domain.Catalog>, Map<String, Map<String, org.jclouds.vcloud.domain.CatalogItem>>>() {
+                  new Function<Map<String, Catalog>, Map<String, Map<String, CatalogItem>>>() {
 
                      @Override
                      public Map<String, Map<String, CatalogItem>> apply(
-                              Map<String, org.jclouds.vcloud.domain.Catalog> from) {
+                              Map<String, Catalog> from) {
                         return transformValues(
                                  from,
-                                 new Function<org.jclouds.vcloud.domain.Catalog, Map<String, org.jclouds.vcloud.domain.CatalogItem>>() {
+                                 new Function<Catalog, Map<String, CatalogItem>>() {
 
                                     @Override
-                                    public Map<String, CatalogItem> apply(org.jclouds.vcloud.domain.Catalog from) {
+                                    public Map<String, CatalogItem> apply(Catalog from) {
                                        return uniqueIndex(filter(allCatalogItemsInCatalog.apply(from), notNull()), name);
                                     }
                                  });
@@ -528,10 +530,10 @@
 
    @Provides
    @Singleton
-   protected Supplier<Map<String, Map<String, Map<String, org.jclouds.vcloud.domain.CatalogItem>>>> provideOrgCatalogItemSupplierCache(
+   protected Supplier<Map<String, Map<String, Map<String, CatalogItem>>>> provideOrgCatalogItemSupplierCache(
             @Named(PROPERTY_SESSION_INTERVAL) long seconds, AtomicReference<AuthorizationException> authException,
             OrgCatalogItemSupplier supplier) {
-      return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<String, Map<String, Map<String, org.jclouds.vcloud.domain.CatalogItem>>>>(
+      return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<String, Map<String, Map<String, CatalogItem>>>>(
                authException, seconds, supplier);
    }
 
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInCatalog.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInCatalog.java
index 5721275..0393f3b 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInCatalog.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInCatalog.java
@@ -31,6 +31,7 @@
 
 import org.jclouds.Constants;
 import org.jclouds.logging.Logger;
+import org.jclouds.util.Iterables2;
 import org.jclouds.vcloud.VCloudAsyncClient;
 import org.jclouds.vcloud.VCloudMediaType;
 import org.jclouds.vcloud.domain.Catalog;
@@ -60,14 +61,14 @@
    @Override
    public Iterable<CatalogItem> apply(Catalog from) {
 
-      Iterable<CatalogItem> catalogItems = transformParallel(filter(from.values(), new Predicate<ReferenceType>() {
+      Iterable<? extends CatalogItem> catalogItems = transformParallel(filter(from.values(), new Predicate<ReferenceType>() {
 
          @Override
          public boolean apply(ReferenceType input) {
             return input.getType().equals(VCloudMediaType.CATALOGITEM_XML);
          }
 
-      }), new Function<ReferenceType, Future<CatalogItem>>() {
+      }), new Function<ReferenceType, Future<? extends CatalogItem>>() {
 
          @Override
          public Future<CatalogItem> apply(ReferenceType from) {
@@ -75,7 +76,7 @@
          }
 
       }, executor, null, logger, "catalogItems in " + from.getHref());
-      return catalogItems;
+      return Iterables2.concreteCopy(catalogItems);
    }
 
 }
\ No newline at end of file
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 fc48add..098940a6 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
@@ -48,9 +48,9 @@
    @Override
    public Iterable<CatalogItem> apply(Org from) {
       return Iterables.concat(Iterables.transform(allCatalogsInOrg.apply(from),
-               new Function<Catalog, Iterable<CatalogItem>>() {
+               new Function<Catalog, Iterable<? extends CatalogItem>>() {
                   @Override
-                  public Iterable<CatalogItem> apply(Catalog from) {
+                  public Iterable<? extends CatalogItem> apply(Catalog from) {
                      return allCatalogItemsInCatalog.apply(from);
                   }
 
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogsInOrg.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogsInOrg.java
index 644b19a..683209f 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogsInOrg.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogsInOrg.java
@@ -30,6 +30,7 @@
 
 import org.jclouds.Constants;
 import org.jclouds.logging.Logger;
+import org.jclouds.util.Iterables2;
 import org.jclouds.vcloud.VCloudAsyncClient;
 import org.jclouds.vcloud.domain.Catalog;
 import org.jclouds.vcloud.domain.Org;
@@ -56,14 +57,14 @@
 
    @Override
    public Iterable<Catalog> apply(final Org org) {
-      Iterable<Catalog> catalogs = transformParallel(org.getCatalogs().values(),
-            new Function<ReferenceType, Future<Catalog>>() {
+      Iterable<? extends Catalog> catalogs = transformParallel(org.getCatalogs().values(),
+            new Function<ReferenceType, Future<? extends Catalog>>() {
                @Override
                public Future<Catalog> apply(ReferenceType from) {
-                  return (Future<Catalog>) aclient.getCatalogClient().getCatalog(from.getHref());
+                  return aclient.getCatalogClient().getCatalog(from.getHref());
                }
 
             }, executor, null, logger, "catalogs in " + org.getName());
-      return catalogs;
+      return Iterables2.concreteCopy(catalogs);
    }
 }
\ No newline at end of file
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllVDCsInOrg.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllVDCsInOrg.java
index 093e951..a65d6d4 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllVDCsInOrg.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllVDCsInOrg.java
@@ -30,6 +30,7 @@
 
 import org.jclouds.Constants;
 import org.jclouds.logging.Logger;
+import org.jclouds.util.Iterables2;
 import org.jclouds.vcloud.VCloudAsyncClient;
 import org.jclouds.vcloud.domain.Org;
 import org.jclouds.vcloud.domain.ReferenceType;
@@ -41,7 +42,7 @@
  * @author Adrian Cole
  */
 @Singleton
-public class AllVDCsInOrg implements Function<Org, Iterable<org.jclouds.vcloud.domain.VDC>> {
+public class AllVDCsInOrg implements Function<Org, Iterable<VDC>> {
    @Resource
    public Logger logger = Logger.NULL;
 
@@ -58,14 +59,14 @@
    public Iterable<VDC> apply(final Org org) {
 
       Iterable<VDC> catalogItems = transformParallel(org.getVDCs().values(),
-            new Function<ReferenceType, Future<org.jclouds.vcloud.domain.VDC>>() {
+            new Function<ReferenceType, Future<? extends VDC>>() {
                @Override
-               public Future<VDC> apply(ReferenceType from) {
+               public Future<? extends VDC> apply(ReferenceType from) {
                   return  aclient.getVDCClient().getVDC(from.getHref());
                }
 
             }, executor, null, logger, "vdcs in org " + org.getName());
-      return catalogItems;
+      return Iterables2.concreteCopy(catalogItems);
    }
 
 }
\ No newline at end of file
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/OrgsForLocations.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/OrgsForLocations.java
index 2d326a7..017d1b1 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/OrgsForLocations.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/OrgsForLocations.java
@@ -35,6 +35,7 @@
 import org.jclouds.domain.Location;
 import org.jclouds.domain.LocationScope;
 import org.jclouds.logging.Logger;
+import org.jclouds.util.Iterables2;
 import org.jclouds.vcloud.VCloudAsyncClient;
 import org.jclouds.vcloud.domain.Org;
 
@@ -46,7 +47,7 @@
  * @author Adrian Cole
  */
 @Singleton
-public class OrgsForLocations implements Function<Iterable<Location>, Iterable< Org>> {
+public class OrgsForLocations implements Function<Iterable<Location>, Iterable<Org>> {
    @Resource
    public Logger logger = Logger.NULL;
    private final VCloudAsyncClient aclient;
@@ -65,7 +66,7 @@
    @Override
    public Iterable<Org> apply(Iterable<Location> from) {
 
-      return transformParallel(Sets.newLinkedHashSet(transform(filter(from, new Predicate<Location>() {
+      return Iterables2.concreteCopy(transformParallel(Sets.newLinkedHashSet(transform(filter(from, new Predicate<Location>() {
 
          @Override
          public boolean apply(Location input) {
@@ -79,14 +80,14 @@
             return URI.create(from.getParent().getId());
          }
 
-      })), new Function<URI, Future<Org>>() {
+      })), new Function<URI, Future<? extends Org>>() {
 
          @Override
          public Future<Org> apply(URI from) {
             return aclient.getOrgClient().getOrg(from);
          }
 
-      }, executor, null, logger, "organizations for uris");
+      }, executor, null, logger, "organizations for uris"));
    }
 
 }
\ No newline at end of file
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/OrgsForNames.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/OrgsForNames.java
index 96e276e..7cf4473 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/OrgsForNames.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/OrgsForNames.java
@@ -30,6 +30,7 @@
 
 import org.jclouds.Constants;
 import org.jclouds.logging.Logger;
+import org.jclouds.util.Iterables2;
 import org.jclouds.vcloud.VCloudAsyncClient;
 import org.jclouds.vcloud.domain.Org;
 
@@ -53,14 +54,14 @@
 
    @Override
    public Iterable<Org> apply(Iterable<String> from) {
-      return transformParallel(from, new Function<String, Future<Org>>() {
+      return Iterables2.concreteCopy(transformParallel(from, new Function<String, Future<? extends Org>>() {
 
          @Override
          public Future<Org> apply(String from) {
             return aclient.getOrgClient().findOrgNamed(from);
          }
 
-      }, executor, null, logger, "organizations for names");
+      }, executor, null, logger, "organizations for names"));
    }
 
 }
\ No newline at end of file
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesForCatalogItems.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesForCatalogItems.java
index 239f27a..4abf213 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesForCatalogItems.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesForCatalogItems.java
@@ -36,6 +36,7 @@
 import org.jclouds.concurrent.Futures;
 import org.jclouds.logging.Logger;
 import org.jclouds.rest.AuthorizationException;
+import org.jclouds.util.Iterables2;
 import org.jclouds.vcloud.VCloudAsyncClient;
 import org.jclouds.vcloud.VCloudMediaType;
 import org.jclouds.vcloud.domain.CatalogItem;
@@ -78,14 +79,14 @@
 
    @Override
    public Iterable<VAppTemplate> apply(Iterable<CatalogItem> from) {
-      return transformParallel(filter(from, new Predicate<CatalogItem>() {
+      return Iterables2.concreteCopy(transformParallel(filter(from, new Predicate<CatalogItem>() {
 
          @Override
          public boolean apply(CatalogItem input) {
             return input.getEntity().getType().equals(VCloudMediaType.VAPPTEMPLATE_XML);
          }
 
-      }), new Function<CatalogItem, Future<VAppTemplate>>() {
+      }), new Function<CatalogItem, Future<? extends VAppTemplate>>() {
 
          @Override
          public Future<VAppTemplate> apply(CatalogItem from) {
@@ -94,7 +95,7 @@
                      returnNullOnAuthorizationException);
          }
 
-      }, executor, null, logger, "vappTemplates in");
+      }, executor, null, logger, "vappTemplates in"));
    }
 
 }
\ 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 b4b733d..1b26580 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
@@ -25,6 +25,7 @@
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
+import org.jclouds.util.Iterables2;
 import org.jclouds.vcloud.domain.CatalogItem;
 import org.jclouds.vcloud.domain.Org;
 import org.jclouds.vcloud.domain.Status;
@@ -53,7 +54,7 @@
    @Override
    public Iterable<VAppTemplate> apply(Org from) {
       Iterable<CatalogItem> catalogs = allCatalogItemsInOrg.apply(from);
-      Iterable<VAppTemplate> vAppTemplates = vAppTemplatesForCatalogItems.apply(catalogs);
+      Iterable<VAppTemplate> vAppTemplates = Iterables2.concreteCopy(vAppTemplatesForCatalogItems.apply(catalogs));
       return filter(vAppTemplates, and(notNull(), new Predicate<VAppTemplate>(){
 
          //TODO: test this
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/suppliers/VAppTemplatesSupplier.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/suppliers/VAppTemplatesSupplier.java
index 05cf929..b96cbc7 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/suppliers/VAppTemplatesSupplier.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/suppliers/VAppTemplatesSupplier.java
@@ -69,8 +69,8 @@
    @Override
    public Set<VAppTemplate> get() {
       Iterable<Org> orgs = checkNotNull(orgMap.get().values(), "orgs");
-      Iterable<Iterable<VAppTemplate>> images = transformParallel(orgs,
-               new Function<Org, Future<Iterable<VAppTemplate>>>() {
+      Iterable<? extends Iterable<VAppTemplate>> images = transformParallel(orgs,
+               new Function<Org, Future<? extends Iterable<VAppTemplate>>>() {
 
                   @Override
                   public Future<Iterable<VAppTemplate>> apply(final Org from) {
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 93edd14..3401069 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
@@ -42,6 +42,7 @@
 import org.jclouds.vcloud.VCloudVersionsClient;
 import org.jclouds.vcloud.config.VCloudRestClientModule;
 import org.jclouds.vcloud.domain.AllocationModel;
+import org.jclouds.vcloud.domain.CatalogItem;
 import org.jclouds.vcloud.domain.Org;
 import org.jclouds.vcloud.domain.ReferenceType;
 import org.jclouds.vcloud.domain.Task;
@@ -253,11 +254,11 @@
          }
 
          @Override
-         public Map<String, Map<String, Map<String, org.jclouds.vcloud.domain.CatalogItem>>> get() {
-            return ImmutableMap.<String, Map<String, Map<String, org.jclouds.vcloud.domain.CatalogItem>>> of(
+         public Map<String, Map<String, Map<String, CatalogItem>>> get() {
+            return ImmutableMap.<String, Map<String, Map<String, CatalogItem>>> of(
                   ORG_REF.getName(), ImmutableMap
-                        .<String, Map<String, org.jclouds.vcloud.domain.CatalogItem>> of(CATALOG_REF
-                              .getName(), ImmutableMap.<String, org.jclouds.vcloud.domain.CatalogItem> of(
+                        .<String, Map<String, CatalogItem>> of(CATALOG_REF
+                              .getName(), ImmutableMap.<String, CatalogItem> of(
                               "template",
                               new CatalogItemImpl("template", URI
                                     .create("https://vcenterprise.bluelock.com/api/v1.0/catalogItem/2"), "description",
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/FetchBlobMetadata.java b/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/FetchBlobMetadata.java
index 613ff0a..3980f89 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/FetchBlobMetadata.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/FetchBlobMetadata.java
@@ -42,6 +42,7 @@
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
 import com.google.inject.Inject;
 
 /**
@@ -83,21 +84,21 @@
    public PageSet<? extends StorageMetadata> apply(PageSet<? extends StorageMetadata> in) {
       checkState(container != null, "container name should be initialized");
 
-      Iterable<BlobMetadata> returnv = transformParallel(Iterables.filter(in, new Predicate<StorageMetadata>() {
+      Iterable<BlobMetadata> returnv = Lists.newArrayList(transformParallel(Iterables.filter(in, new Predicate<StorageMetadata>() {
 
          @Override
          public boolean apply(StorageMetadata input) {
             return input.getType() == StorageType.BLOB;
          }
 
-      }), new Function<StorageMetadata, Future<BlobMetadata>>() {
+      }), new Function<StorageMetadata, Future<? extends BlobMetadata>>() {
 
          @Override
          public Future<BlobMetadata> apply(StorageMetadata from) {
             return ablobstore.blobMetadata(container, from.getName());
          }
 
-      }, userExecutor, maxTime, logger, String.format("getting metadata from containerName: %s", container));
+      }, userExecutor, maxTime, logger, String.format("getting metadata from containerName: %s", container)));
 
       return new PageSetImpl<BlobMetadata>(returnv, in.getNextMarker());
    }
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/GetAllBlobsInListAndRetryOnFailure.java b/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/GetAllBlobsInListAndRetryOnFailure.java
index 00adf8e..316a522 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/GetAllBlobsInListAndRetryOnFailure.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/GetAllBlobsInListAndRetryOnFailure.java
@@ -75,7 +75,7 @@
 
    public Iterable<Blob> execute(final String container, ListContainerOptions options) {
       Iterable<? extends BlobMetadata> list = getAllBlobMetadata.execute(container, options);
-      return transformParallel(list, new Function<BlobMetadata, Future<Blob>>() {
+      return transformParallel(list, new Function<BlobMetadata, Future<? extends Blob>>() {
 
          @Override
          public Future<Blob> apply(BlobMetadata from) {
diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/TerremarkVCloudComputeService.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/TerremarkVCloudComputeService.java
index 8710791..723e886 100644
--- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/TerremarkVCloudComputeService.java
+++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/TerremarkVCloudComputeService.java
@@ -31,6 +31,7 @@
 import org.jclouds.Constants;
 import org.jclouds.collect.Memoized;
 import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.compute.ImageExtension;
 import org.jclouds.compute.callables.RunScriptOnNode;
 import org.jclouds.compute.domain.Hardware;
 import org.jclouds.compute.domain.Image;
@@ -54,6 +55,7 @@
 import org.jclouds.trmk.vcloud_0_8.compute.options.TerremarkVCloudTemplateOptions;
 import org.jclouds.trmk.vcloud_0_8.compute.strategy.CleanupOrphanKeys;
 
+import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;
 
@@ -78,12 +80,13 @@
          InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
          RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
          PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
-         @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, CleanupOrphanKeys cleanupOrphanKeys) {
+         @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, CleanupOrphanKeys cleanupOrphanKeys,
+         Optional<ImageExtension> imageExtension) {
       super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
             runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, resumeNodeStrategy,
             suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
             nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials,
-            timeouts, executor);
+            timeouts, executor, imageExtension);
       this.cleanupOrphanKeys = cleanupOrphanKeys;
    }
 
diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/suppliers/VCloudHardwareSupplier.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/suppliers/VCloudHardwareSupplier.java
index b0bdee1..bdc97a1 100644
--- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/suppliers/VCloudHardwareSupplier.java
+++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/suppliers/VCloudHardwareSupplier.java
@@ -69,8 +69,8 @@
    @Override
    public Set<? extends Hardware> get() {
       Iterable<? extends Org> orgs = checkNotNull(orgMap.get().values(), "orgs");
-      Iterable<Iterable<? extends Hardware>> sizes = transformParallel(orgs,
-               new Function<Org, Future<Iterable<? extends Hardware>>>() {
+      Iterable<? extends Iterable<? extends Hardware>> sizes = transformParallel(orgs,
+               new Function<Org, Future<? extends Iterable<? extends Hardware>>>() {
 
                   @Override
                   public Future<Iterable<? extends Hardware>> apply(final Org from) {
diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/suppliers/VCloudImageSupplier.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/suppliers/VCloudImageSupplier.java
index d636b15..e279a64 100644
--- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/suppliers/VCloudImageSupplier.java
+++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/suppliers/VCloudImageSupplier.java
@@ -69,8 +69,8 @@
    @Override
    public Set<? extends Image> get() {
       Iterable<? extends Org> orgs = checkNotNull(orgMap.get().values(), "orgs");
-      Iterable<Iterable<? extends Image>> images = transformParallel(orgs,
-               new Function<Org, Future<Iterable<? extends Image>>>() {
+      Iterable<? extends Iterable<? extends Image>> images = transformParallel(orgs,
+               new Function<Org, Future<? extends Iterable<? extends Image>>>() {
 
                   @Override
                   public Future<Iterable<? extends Image>> apply(final Org from) {
diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllCatalogItemsInCatalog.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllCatalogItemsInCatalog.java
index 3740de3..effb137 100644
--- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllCatalogItemsInCatalog.java
+++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllCatalogItemsInCatalog.java
@@ -61,14 +61,14 @@
    @Override
    public Iterable<? extends CatalogItem> apply(Catalog from) {
 
-      Iterable<CatalogItem> catalogItems = transformParallel(filter(from.values(), new Predicate<ReferenceType>() {
+      Iterable<? extends CatalogItem> catalogItems = transformParallel(filter(from.values(), new Predicate<ReferenceType>() {
 
          @Override
          public boolean apply(ReferenceType input) {
             return input.getType().equals(TerremarkVCloudMediaType.CATALOGITEM_XML);
          }
 
-      }), new Function<ReferenceType, Future<CatalogItem>>() {
+      }), new Function<ReferenceType, Future<? extends CatalogItem>>() {
 
          @SuppressWarnings("unchecked")
          @Override
diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllCatalogsInOrg.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllCatalogsInOrg.java
index 66e7979..a2ac27f 100644
--- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllCatalogsInOrg.java
+++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllCatalogsInOrg.java
@@ -56,8 +56,8 @@
 
    @Override
    public Iterable<? extends Catalog> apply(final Org org) {
-      Iterable<Catalog> catalogs = transformParallel(org.getCatalogs().values(),
-            new Function<ReferenceType, Future<Catalog>>() {
+      Iterable<? extends Catalog> catalogs = transformParallel(org.getCatalogs().values(),
+            new Function<ReferenceType, Future<? extends Catalog>>() {
                @SuppressWarnings("unchecked")
                @Override
                public Future<Catalog> apply(ReferenceType from) {
diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllVDCsInOrg.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllVDCsInOrg.java
index 3ef54d8..28307a3 100644
--- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllVDCsInOrg.java
+++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllVDCsInOrg.java
@@ -56,12 +56,11 @@
    @Override
    public Iterable<? extends org.jclouds.trmk.vcloud_0_8.domain.VDC> apply(final Org org) {
 
-      Iterable<org.jclouds.trmk.vcloud_0_8.domain.VDC> catalogItems = transformParallel(org.getVDCs().values(),
-            new Function<ReferenceType, Future<org.jclouds.trmk.vcloud_0_8.domain.VDC>>() {
-               @SuppressWarnings("unchecked")
+      Iterable<? extends org.jclouds.trmk.vcloud_0_8.domain.VDC> catalogItems = transformParallel(org.getVDCs().values(),
+            new Function<ReferenceType, Future<? extends org.jclouds.trmk.vcloud_0_8.domain.VDC>>() {
                @Override
-               public Future<org.jclouds.trmk.vcloud_0_8.domain.VDC> apply(ReferenceType from) {
-                  return (Future<org.jclouds.trmk.vcloud_0_8.domain.VDC>) aclient.getVDC(from.getHref());
+               public Future<? extends org.jclouds.trmk.vcloud_0_8.domain.VDC> apply(ReferenceType from) {
+                  return aclient.getVDC(from.getHref());
                }
 
             }, executor, null, logger, "vdcs in org " + org.getName());
diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/OrgsForLocations.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/OrgsForLocations.java
index 568203e..00f79b4 100644
--- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/OrgsForLocations.java
+++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/OrgsForLocations.java
@@ -79,12 +79,10 @@
             return URI.create(from.getParent().getId());
          }
 
-      })), new Function<URI, Future<Org>>() {
-
-         @SuppressWarnings("unchecked")
+      })), new Function<URI, Future<? extends Org>>() {
          @Override
-         public Future<Org> apply(URI from) {
-            return (Future<Org>) aclient.getOrg(from);
+         public Future<? extends Org> apply(URI from) {
+            return aclient.getOrg(from);
          }
 
       }, executor, null, logger, "organizations for uris");
diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/OrgsForNames.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/OrgsForNames.java
index 1c95f0e..7408430 100644
--- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/OrgsForNames.java
+++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/OrgsForNames.java
@@ -53,12 +53,10 @@
 
    @Override
    public Iterable<? extends Org> apply(Iterable<String> from) {
-      return transformParallel(from, new Function<String, Future<Org>>() {
-
-         @SuppressWarnings("unchecked")
+      return transformParallel(from, new Function<String, Future<? extends Org>>() {
          @Override
-         public Future<Org> apply(String from) {
-            return (Future<Org>) aclient.findOrgNamed(from);
+         public Future<? extends Org> apply(String from) {
+            return aclient.findOrgNamed(from);
          }
 
       }, executor, null, logger, "organizations for names");
diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/VAppTemplatesForCatalogItems.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/VAppTemplatesForCatalogItems.java
index 6995b71..2fbabe4 100644
--- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/VAppTemplatesForCatalogItems.java
+++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/VAppTemplatesForCatalogItems.java
@@ -68,12 +68,10 @@
             return input.getEntity().getType().equals(TerremarkVCloudMediaType.VAPPTEMPLATE_XML);
          }
 
-      }), new Function<CatalogItem, Future<VAppTemplate>>() {
-
-         @SuppressWarnings("unchecked")
+      }), new Function<CatalogItem, Future<? extends VAppTemplate>>() {
          @Override
-         public Future<VAppTemplate> apply(CatalogItem from) {
-            return (Future<VAppTemplate>) aclient.getVAppTemplate(from.getEntity().getHref());
+         public Future<? extends VAppTemplate> apply(CatalogItem from) {
+            return aclient.getVAppTemplate(from.getEntity().getHref());
          }
 
       }, executor, null, logger, "vappTemplates in");
diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/VAppTemplatesForResourceEntities.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/VAppTemplatesForResourceEntities.java
index e096c28..ee9bb1a 100644
--- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/VAppTemplatesForResourceEntities.java
+++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/VAppTemplatesForResourceEntities.java
@@ -69,12 +69,10 @@
             return input.getType().equals(TerremarkVCloudMediaType.VAPPTEMPLATE_XML);
          }
 
-      }), new Function<ReferenceType, Future<VAppTemplate>>() {
-
-         @SuppressWarnings("unchecked")
+      }), new Function<ReferenceType, Future<? extends VAppTemplate>>() {
          @Override
-         public Future<VAppTemplate> apply(ReferenceType from) {
-            return (Future<VAppTemplate>) aclient.getVAppTemplate(from.getHref());
+         public Future<? extends VAppTemplate> apply(ReferenceType from) {
+            return aclient.getVAppTemplate(from.getHref());
          }
 
       }, executor, null, logger, "vappTemplates in");
diff --git a/compute/src/main/java/org/jclouds/compute/ComputeService.java b/compute/src/main/java/org/jclouds/compute/ComputeService.java
index 701f8f3..3c04e8a 100644
--- a/compute/src/main/java/org/jclouds/compute/ComputeService.java
+++ b/compute/src/main/java/org/jclouds/compute/ComputeService.java
@@ -38,6 +38,7 @@
 import org.jclouds.scriptbuilder.domain.Statement;
 
 import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.inject.ImplementedBy;
@@ -345,5 +346,14 @@
     * @see #runScriptOnNode(String, String, RunScriptOptions)
     */
    ExecResponse runScriptOnNode(String id, String runScript);
+   
+   /**
+    * Returns the {@link ImageExtension} for this provider if it implements it.
+    * 
+    * @return an optional of the {@link ImageExtension} or {@link Optional#absent()} if not
+    *         implemented
+    */
+   @Beta
+   Optional<ImageExtension> getImageExtension();
 
 }
diff --git a/compute/src/main/java/org/jclouds/compute/ImageExtension.java b/compute/src/main/java/org/jclouds/compute/ImageExtension.java
new file mode 100644
index 0000000..56da218
--- /dev/null
+++ b/compute/src/main/java/org/jclouds/compute/ImageExtension.java
@@ -0,0 +1,63 @@
+/**
+ * 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.compute;
+
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.ImageTemplate;
+
+/**
+ * An extension to compute service to allow for the manipulation of {@link Image}s. Implementation
+ * is optional by providers.
+ * 
+ * @author David Alves
+ */
+public interface ImageExtension {
+
+   /**
+    * Build an ImageTemplate from a running node, to use later to create a new {@link Image}.
+    * 
+    * @param name
+    *           name to give the new image
+    * 
+    * @param id
+    *           node to base the template on
+    * @return an image template that can be used to create a new image
+    */
+   ImageTemplate buildImageTemplateFromNode(String name, String id);
+
+   /**
+    * Transform the {@link ImageTemplate} on an {@link Image} that can be used to create nodes.
+    * 
+    * @param template
+    *           template to base the new image on
+    * @return the image that was just built *after* it is registered on the provider
+    */
+   Image createImage(ImageTemplate template);
+
+   /**
+    * Delete an {@link Image} on the provider.
+    * 
+    * @param id
+    *           the id of the image to delete
+    * @return
+    */
+   boolean deleteImage(String id);
+
+}
diff --git a/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java b/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java
index ecc4774..a522f13 100644
--- a/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java
+++ b/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java
@@ -31,6 +31,7 @@
 import javax.inject.Singleton;
 
 import org.jclouds.collect.Memoized;
+import org.jclouds.compute.ImageExtension;
 import org.jclouds.compute.callables.BlockUntilInitScriptStatusIsZeroThenReturnOutput;
 import org.jclouds.compute.callables.RunScriptOnNode;
 import org.jclouds.compute.callables.RunScriptOnNodeAsInitScriptUsingSsh;
@@ -61,6 +62,7 @@
 import org.jclouds.ssh.SshClient;
 
 import com.google.common.base.Function;
+import com.google.common.base.Optional;
 import com.google.common.base.Supplier;
 import com.google.common.base.Suppliers;
 import com.google.common.collect.ImmutableMap;
@@ -299,5 +301,12 @@
          }
       };
    }
+   
+   @Provides
+   @Singleton
+   protected Optional<ImageExtension> provideImageExtension(Injector i){
+      return Optional.absent();
+   }
+   
 
 }
\ No newline at end of file
diff --git a/compute/src/main/java/org/jclouds/compute/domain/CloneImageTemplate.java b/compute/src/main/java/org/jclouds/compute/domain/CloneImageTemplate.java
new file mode 100644
index 0000000..238fdef
--- /dev/null
+++ b/compute/src/main/java/org/jclouds/compute/domain/CloneImageTemplate.java
@@ -0,0 +1,31 @@
+/**
+ * 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.compute.domain;
+
+/**
+ * An {@link ImageTemplate} for the purpose of cloning an existing node.
+ * 
+ * @author David Alves
+ */
+public interface CloneImageTemplate extends ImageTemplate {
+
+   public String getSourceNodeId();
+
+}
diff --git a/compute/src/main/java/org/jclouds/compute/domain/ImageTemplate.java b/compute/src/main/java/org/jclouds/compute/domain/ImageTemplate.java
new file mode 100644
index 0000000..651a899
--- /dev/null
+++ b/compute/src/main/java/org/jclouds/compute/domain/ImageTemplate.java
@@ -0,0 +1,35 @@
+/**
+ * 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.compute.domain;
+
+/**
+ * A template for building new {@link Image}s.
+ * 
+ * @author David Alves
+ * 
+ */
+public interface ImageTemplate {
+
+   /**
+    * @return the name of the new image
+    */
+   public String getName();
+
+}
diff --git a/compute/src/main/java/org/jclouds/compute/domain/ImageTemplateBuilder.java b/compute/src/main/java/org/jclouds/compute/domain/ImageTemplateBuilder.java
new file mode 100644
index 0000000..6104cd9
--- /dev/null
+++ b/compute/src/main/java/org/jclouds/compute/domain/ImageTemplateBuilder.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.compute.domain;
+
+import org.jclouds.compute.domain.internal.ImageTemplateImpl;
+
+/**
+ * A builder for {@link ImageTemplate}s. Includes sub-builders to build specific
+ * {@link ImageTemplate}s for different purposes, such as cloning, creating from iso, creating from
+ * netboot.
+ * 
+ * @author David Alves
+ * 
+ */
+public abstract class ImageTemplateBuilder {
+
+   String name;
+
+   private ImageTemplateBuilder() {
+   }
+
+   public ImageTemplateBuilder name(String name) {
+      this.name = name;
+      return this;
+   }
+
+   public static class CloneImageTemplateBuilder extends ImageTemplateBuilder {
+
+      String nodeId;
+
+      @Override
+      public CloneImageTemplateBuilder name(String name) {
+         return CloneImageTemplateBuilder.class.cast(super.name(name));
+      }
+
+      public CloneImageTemplateBuilder nodeId(String nodeId) {
+         this.nodeId = nodeId;
+         return this;
+      }
+
+      public CloneImageTemplate build() {
+         return new ImageTemplateImpl.CloneImageTemplateImpl(name, nodeId);
+      }
+   }
+}
diff --git a/compute/src/main/java/org/jclouds/compute/domain/internal/ImageTemplateImpl.java b/compute/src/main/java/org/jclouds/compute/domain/internal/ImageTemplateImpl.java
new file mode 100644
index 0000000..2745f17
--- /dev/null
+++ b/compute/src/main/java/org/jclouds/compute/domain/internal/ImageTemplateImpl.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.compute.domain.internal;
+
+import org.jclouds.compute.domain.CloneImageTemplate;
+import org.jclouds.compute.domain.ImageTemplate;
+
+public abstract class ImageTemplateImpl implements ImageTemplate {
+
+   protected final String name;
+
+   public ImageTemplateImpl(String name) {
+      this.name = name;
+   }
+
+   @Override
+   public String getName() {
+      return this.name;
+   }
+
+   public static class CloneImageTemplateImpl extends ImageTemplateImpl implements CloneImageTemplate {
+
+      protected final String sourceNodeId;
+
+      public CloneImageTemplateImpl(String name, String sourceNodeId) {
+         super(name);
+         this.sourceNodeId = sourceNodeId;
+      }
+
+      @Override
+      public String getSourceNodeId() {
+         return this.sourceNodeId;
+      }
+   }
+
+}
diff --git a/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java b/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java
index bd4496b..90a7538 100644
--- a/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java
+++ b/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java
@@ -51,6 +51,7 @@
 import org.jclouds.collect.Memoized;
 import org.jclouds.compute.ComputeService;
 import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.compute.ImageExtension;
 import org.jclouds.compute.RunNodesException;
 import org.jclouds.compute.RunScriptOnNodesException;
 import org.jclouds.compute.callables.RunScriptOnNode;
@@ -90,6 +91,7 @@
 import org.jclouds.util.Maps2;
 
 import com.google.common.base.Function;
+import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;
 import com.google.common.collect.ImmutableMap;
@@ -134,6 +136,7 @@
    private final PersistNodeCredentials persistNodeCredentials;
    private final RunScriptOnNode.Factory runScriptOnNodeFactory;
    private final ExecutorService executor;
+   private final Optional<ImageExtension> imageExtension;
 
    @Inject
    protected BaseComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore,
@@ -148,7 +151,8 @@
          @Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
          InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess,
          RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials,
-         Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
+         Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor,
+         Optional<ImageExtension> imageExtension) {
       this.context = checkNotNull(context, "context");
       this.credentialStore = checkNotNull(credentialStore, "credentialStore");
       this.images = checkNotNull(images, "images");
@@ -172,6 +176,7 @@
       this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory, "runScriptOnNodeFactory");
       this.persistNodeCredentials = checkNotNull(persistNodeCredentials, "persistNodeCredentials");
       this.executor = checkNotNull(executor, "executor");
+      this.imageExtension = imageExtension;
    }
 
    /**
@@ -238,7 +243,7 @@
    public Set<? extends NodeMetadata> destroyNodesMatching(Predicate<NodeMetadata> filter) {
       logger.debug(">> destroying nodes matching(%s)", filter);
       Set<NodeMetadata> set = newLinkedHashSet(filter(transformParallel(nodesMatchingFilterAndNotTerminated(filter),
-            new Function<NodeMetadata, Future<NodeMetadata>>() {
+            new Function<NodeMetadata, Future<? extends NodeMetadata>>() {
 
                // TODO make an async interface instead of re-wrapping
                @Override
@@ -403,7 +408,7 @@
    public void rebootNodesMatching(Predicate<NodeMetadata> filter) {
       logger.debug(">> rebooting nodes matching(%s)", filter);
       transformParallel(nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter),
-            new Function<NodeMetadata, Future<Void>>() {
+            new Function<NodeMetadata, Future<? extends Void>>() {
                // TODO use native async
                @Override
                public Future<Void> apply(NodeMetadata from) {
@@ -434,7 +439,7 @@
    public void resumeNodesMatching(Predicate<NodeMetadata> filter) {
       logger.debug(">> resuming nodes matching(%s)", filter);
       transformParallel(nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter),
-            new Function<NodeMetadata, Future<Void>>() {
+            new Function<NodeMetadata, Future<? extends Void>>() {
                // TODO use native async
                @Override
                public Future<Void> apply(NodeMetadata from) {
@@ -465,7 +470,7 @@
    public void suspendNodesMatching(Predicate<NodeMetadata> filter) {
       logger.debug(">> suspending nodes matching(%s)", filter);
       transformParallel(nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter),
-            new Function<NodeMetadata, Future<Void>>() {
+            new Function<NodeMetadata, Future<? extends Void>>() {
                // TODO use native async
                @Override
                public Future<Void> apply(NodeMetadata from) {
@@ -649,7 +654,7 @@
    }
 
    private final class TransformNodesIntoInitializedScriptRunners implements
-         Function<NodeMetadata, Future<RunScriptOnNode>> {
+         Function<NodeMetadata, Future<? extends RunScriptOnNode>> {
       private final Map<NodeMetadata, Exception> badNodes;
       private final Statement script;
       private final RunScriptOptions options;
@@ -668,5 +673,13 @@
       }
 
    }
+   
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public Optional<ImageExtension> getImageExtension() {
+      return imageExtension;
+   }
 
 }
\ No newline at end of file
diff --git a/compute/src/test/java/org/jclouds/compute/internal/BaseImageExtensionLiveTest.java b/compute/src/test/java/org/jclouds/compute/internal/BaseImageExtensionLiveTest.java
new file mode 100644
index 0000000..896e1ff
--- /dev/null
+++ b/compute/src/test/java/org/jclouds/compute/internal/BaseImageExtensionLiveTest.java
@@ -0,0 +1,134 @@
+/**
+ * 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.compute.internal;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import java.util.Set;
+
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.ImageExtension;
+import org.jclouds.compute.RunNodesException;
+import org.jclouds.compute.domain.ExecResponse;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.ImageTemplate;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.ssh.SshClient;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+
+/**
+ * Base test for {@link ImageExtension} implementations.
+ * 
+ * @author David Alves
+ * 
+ */
+public abstract class BaseImageExtensionLiveTest extends BaseComputeServiceContextLiveTest {
+
+   /**
+    * Returns the template for the base node, override to test different templates.
+    * 
+    * @return
+    */
+   public Template getNodeTemplate() {
+      return context.getComputeService().templateBuilder().any().build();
+   }
+
+   @Test(groups = { "integration", "live" }, singleThreaded = true)
+   public void testCreateImage() throws RunNodesException, InterruptedException {
+
+      ComputeService computeService = context.getComputeService();
+
+      Optional<ImageExtension> imageExtension = computeService.getImageExtension();
+      assertTrue("image extension was not present", imageExtension.isPresent());
+
+      Set<? extends Image> imagesBefore = computeService.listImages();
+
+      NodeMetadata node = Iterables.getOnlyElement(computeService.createNodesInGroup("test-create-image", 1,
+               getNodeTemplate()));
+
+      ImageTemplate newImageTemplate = imageExtension.get().buildImageTemplateFromNode("test-create-image",
+               node.getId());
+
+      Image image = imageExtension.get().createImage(newImageTemplate);
+
+      assertEquals("test-create-image", image.getName());
+
+      computeService.destroyNode(node.getId());
+
+      Set<? extends Image> imagesAfter = computeService.listImages();
+
+      assertTrue(imagesBefore.size() == imagesAfter.size() - 1);
+
+   }
+
+   @Test(groups = { "integration", "live" }, singleThreaded = true, dependsOnMethods = "testCreateImage")
+   public void testSpawnNodeFromImage() throws RunNodesException {
+
+      ComputeService computeService = context.getComputeService();
+
+      Template template = computeService.templateBuilder().fromImage(getImage().get()).build();
+
+      NodeMetadata node = Iterables.getOnlyElement(computeService.createNodesInGroup("test-create-image", 1, template));
+
+      SshClient client = context.utils().sshForNode().apply(node);
+      client.connect();
+
+      ExecResponse hello = client.exec("echo hello");
+
+      assertEquals(hello.getOutput().trim(), "hello");
+
+      context.getComputeService().destroyNode(node.getId());
+
+   }
+
+   @Test(groups = { "integration", "live" }, singleThreaded = true, dependsOnMethods = { "testCreateImage",
+            "testSpawnNodeFromImage" })
+   public void testDeleteImage() {
+
+      ComputeService computeService = context.getComputeService();
+
+      Optional<ImageExtension> imageExtension = computeService.getImageExtension();
+      assertTrue("image extension was not present", imageExtension.isPresent());
+
+      Optional<? extends Image> optImage = getImage();
+
+      assertTrue(optImage.isPresent());
+
+      Image image = optImage.get();
+
+      assertTrue(imageExtension.get().deleteImage(image.getId()));
+   }
+
+   private Optional<? extends Image> getImage() {
+      return Iterables.tryFind(context.getComputeService().listImages(), new Predicate<Image>() {
+         @Override
+         public boolean apply(Image input) {
+            return input.getId().contains("test-create-image");
+         }
+      });
+   }
+
+}
diff --git a/core/pom.xml b/core/pom.xml
index 9f1b049..b63f5e9 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -99,7 +99,7 @@
         <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
-            <version>12.0-rc1</version>
+            <version>12.0-rc2</version>
         </dependency>
     </dependencies>
 
diff --git a/core/src/main/java/org/jclouds/concurrent/FutureIterables.java b/core/src/main/java/org/jclouds/concurrent/FutureIterables.java
index 5fe7671..2655df9 100644
--- a/core/src/main/java/org/jclouds/concurrent/FutureIterables.java
+++ b/core/src/main/java/org/jclouds/concurrent/FutureIterables.java
@@ -58,50 +58,51 @@
 public class FutureIterables {
    @Resource
    private static Logger logger = Logger.CONSOLE;
-
+   
    @Inject(optional = true)
    @Named(Constants.PROPERTY_MAX_RETRIES)
    private static int maxRetries = 5;
-
+   
    @Inject(optional = true)
    @Named(Constants.PROPERTY_RETRY_DELAY_START)
    private static long delayStart = 50L;
-
+   
    @Inject(optional = true)
    private static BackoffLimitedRetryHandler retryHandler = BackoffLimitedRetryHandler.INSTANCE;
-
+   
    public static <F, T> Iterable<T> transformParallel(final Iterable<F> fromIterable,
-            final Function<? super F, Future<T>> function) {
+         final Function<? super F, Future<? extends T>> function) {
       return transformParallel(fromIterable, function, org.jclouds.concurrent.MoreExecutors.sameThreadExecutor(), null);
    }
-
+   
    public static <F, T> Iterable<T> transformParallel(final Iterable<F> fromIterable,
-            final Function<? super F, Future<T>> function, ExecutorService exec, @Nullable Long maxTime) {
+         final Function<? super F, Future<? extends T>> function, ExecutorService exec, @Nullable Long maxTime) {
       return transformParallel(fromIterable, function, exec, maxTime, logger, "transforming");
    }
-
+   
    public static <F, T> Iterable<T> transformParallel(final Iterable<F> fromIterable,
-            final Function<? super F, Future<T>> function, ExecutorService exec, @Nullable Long maxTime, Logger logger,
-            String logPrefix) {
+         final Function<? super F, Future<? extends T>> function, ExecutorService exec, @Nullable Long maxTime, Logger logger,
+               String logPrefix) {
       return transformParallel(fromIterable, function, exec, maxTime, logger, logPrefix, retryHandler, maxRetries);
    }
-
+   
    @SuppressWarnings("unchecked")
    public static <F, T> Iterable<T> transformParallel(Iterable<F> fromIterable,
-            Function<? super F, Future<T>> function, ExecutorService exec, @Nullable Long maxTime, Logger logger,
-            String logPrefix, BackoffLimitedRetryHandler retryHandler, int maxRetries) {
+         Function<? super F, Future<? extends T>> function, ExecutorService exec, @Nullable Long maxTime, Logger logger,
+               String logPrefix, BackoffLimitedRetryHandler retryHandler, int maxRetries) {
       Map<F, Exception> exceptions = newHashMap();
-      Map<F, Future<T>> responses = newHashMap();
+      Map<F, Future<? extends T>> responses = newHashMap();
       for (int i = 0; i < maxRetries; i++) {
-
+         
          for (F from : fromIterable) {
-            responses.put(from, function.apply(from));
+            Future<? extends T> to = function.apply(from);
+            responses.put(from, to);
          }
          exceptions = awaitCompletion(responses, exec, maxTime, logger, logPrefix);
          if (exceptions.size() > 0 && !any(exceptions.values(), containsThrowable(AuthorizationException.class))) {
             fromIterable = exceptions.keySet();
             retryHandler.imposeBackoffExponentialDelay(delayStart, 2, i + 1, maxRetries,
-                     String.format("error %s: %s: %s", logPrefix, fromIterable, exceptions));
+                  String.format("error %s: %s: %s", logPrefix, fromIterable, exceptions));
          } else {
             break;
          }
@@ -109,13 +110,13 @@
       //make sure we propagate any authorization exception so that we don't lock out accounts
       if (exceptions.size() > 0)
          return propagateAuthorizationOrOriginalException(new TransformParallelException((Map) responses, exceptions,
-                  logPrefix));
-
+               logPrefix));
+      
       return unwrap(responses.values());
    }
-
+   
    public static <T> Map<T, Exception> awaitCompletion(Map<T, ? extends Future<?>> responses, ExecutorService exec,
-            @Nullable Long maxTime, final Logger logger, final String logPrefix) {
+         @Nullable Long maxTime, final Logger logger, final String logPrefix) {
       final ConcurrentMap<T, Exception> errorMap = newConcurrentMap();
       if (responses.size() == 0)
          return errorMap;
@@ -126,7 +127,7 @@
       final long start = System.currentTimeMillis();
       for (final java.util.Map.Entry<T, ? extends Future<?>> future : responses.entrySet()) {
          Futures.makeListenable(future.getValue(), exec).addListener(new Runnable() {
-
+            
             @Override
             public void run() {
                try {
@@ -168,11 +169,11 @@
       }
       return errorMap;
    }
-
-   public static <T> Iterable<T> unwrap(Iterable<Future<T>> values) {
-      return transform(values, new Function<Future<T>, T>() {
+   
+   public static <T> Iterable<T> unwrap(Iterable<Future<? extends T>> values) {
+      return transform(values, new Function<Future<? extends T>, T>() {
          @Override
-         public T apply(Future<T> from) {
+         public T apply(Future<? extends T> from) {
             try {
                return from.get();
             } catch (InterruptedException e) {
@@ -189,20 +190,20 @@
          }
       });
    }
-
+   
    private static void logException(Logger logger, String logPrefix, int total, int complete, int errors, long start,
-            Exception e) {
+         Exception e) {
       String message = message(logPrefix, total, complete, errors, start);
       logger.error(e, message);
    }
-
+   
    private static String message(String prefix, int size, int complete, int errors, long start) {
       return String.format("%s, completed: %d/%d, errors: %d, rate: %dms/op", prefix, complete, size, errors,
-               (long) ((System.currentTimeMillis() - start) / ((double) size)));
+            (long) ((System.currentTimeMillis() - start) / ((double) size)));
    }
-
+   
    protected static boolean timeOut(long start, Long maxTime) {
       return maxTime != null ? System.currentTimeMillis() < start + maxTime : false;
    }
-
+   
 }
\ No newline at end of file
diff --git a/core/src/main/java/org/jclouds/util/Iterables2.java b/core/src/main/java/org/jclouds/util/Iterables2.java
new file mode 100644
index 0000000..886a6d0
--- /dev/null
+++ b/core/src/main/java/org/jclouds/util/Iterables2.java
@@ -0,0 +1,40 @@
+/**
+ * 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.util;
+
+import com.google.common.collect.ImmutableSortedSet;
+
+/**
+ * General utilities used in jclouds code for {@link Iterable Iterables}.
+ * 
+ * @author danikov
+ */
+public class Iterables2 {
+
+   /**
+    * Copies the contents of a wildcarded {@link Iterable} into a concrete {@link Iterable} of the left bound
+    * 
+    * @param unboundedValues wildcarded source {@link Iterable}
+    * @return concrete-typed copy of the source
+    */
+   public static <T> Iterable<T> concreteCopy(Iterable<? extends T> unboundedValues) {
+      return ImmutableSortedSet.copyOf(unboundedValues);
+   }
+   
+}
diff --git a/core/src/main/java/org/jclouds/util/Maps2.java b/core/src/main/java/org/jclouds/util/Maps2.java
index 8150d8e..324995e 100644
--- a/core/src/main/java/org/jclouds/util/Maps2.java
+++ b/core/src/main/java/org/jclouds/util/Maps2.java
@@ -154,5 +154,15 @@
        }
        return result;
    }
+   
+   /**
+    * Covariant compatible version
+    * 
+    * @see {@link Maps#uniqueIndex(Iterable, Function)}
+    */
+   public static <K, V> ImmutableMap<K, V> uniqueIndex(
+         Iterable<? extends V> values, Function<? super V, ? extends K> keyFunction) {
+      return ImmutableMap.copyOf(Maps.uniqueIndex(values, keyFunction));
+   }
 
 }
diff --git a/core/src/test/java/org/jclouds/concurrent/FutureIterablesTest.java b/core/src/test/java/org/jclouds/concurrent/FutureIterablesTest.java
index 0601ede..2071454 100644
--- a/core/src/test/java/org/jclouds/concurrent/FutureIterablesTest.java
+++ b/core/src/test/java/org/jclouds/concurrent/FutureIterablesTest.java
@@ -43,7 +43,7 @@
       final AtomicInteger counter = new AtomicInteger();
 
       try {
-         transformParallel(ImmutableSet.of("hello", "goodbye"), new Function<String, Future<String>>() {
+         transformParallel(ImmutableSet.of("hello", "goodbye"), new Function<String, Future<? extends String>>() {
 
             @Override
             public Future<String> apply(String input) {
@@ -63,7 +63,7 @@
       final AtomicInteger counter = new AtomicInteger();
 
       try {
-         transformParallel(ImmutableSet.of("hello", "goodbye"), new Function<String, Future<String>>() {
+         transformParallel(ImmutableSet.of("hello", "goodbye"), new Function<String, Future<? extends String>>() {
 
             @Override
             public Future<String> apply(String input) {
diff --git a/core/src/test/java/org/jclouds/rest/internal/BaseRestClientExpectTest.java b/core/src/test/java/org/jclouds/rest/internal/BaseRestClientExpectTest.java
index 88e6758..8e77a56 100644
--- a/core/src/test/java/org/jclouds/rest/internal/BaseRestClientExpectTest.java
+++ b/core/src/test/java/org/jclouds/rest/internal/BaseRestClientExpectTest.java
@@ -22,11 +22,13 @@
 import static org.testng.Assert.assertEquals;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Properties;
 import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.logging.Logger;
@@ -57,11 +59,13 @@
 import org.jclouds.http.handlers.DelegatingRetryHandler;
 import org.jclouds.http.internal.BaseHttpCommandExecutorService;
 import org.jclouds.http.internal.HttpWire;
+import org.jclouds.io.CopyInputStreamInputSupplierMap;
 import org.jclouds.io.Payload;
 import org.jclouds.io.Payloads;
 import org.jclouds.logging.config.NullLoggingModule;
 import org.jclouds.providers.ProviderMetadata;
 import org.jclouds.rest.RestApiMetadata;
+import org.jclouds.rest.config.CredentialStoreModule;
 import org.jclouds.util.Strings2;
 import org.testng.annotations.Test;
 import org.w3c.dom.Node;
@@ -74,6 +78,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.io.InputSupplier;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonParser;
 import com.google.inject.AbstractModule;
@@ -540,11 +545,13 @@
 
       this.api = RestApiMetadata.class.cast(builder.getApiMetadata()).getApi();
 
+      // isolate tests from eachother, as default credentialStore is static
       return builder.credentials(identity, credential).modules(
-               ImmutableSet.of(new ExpectModule(fn), new NullLoggingModule(), module)).overrides(setupProperties())
+               ImmutableSet.of(new ExpectModule(fn), new NullLoggingModule(), new CredentialStoreModule(new CopyInputStreamInputSupplierMap(
+                     new ConcurrentHashMap<String, InputSupplier<InputStream>>())), module)).overrides(setupProperties())
                .buildInjector();
    }
-
+   
    /**
     * override this to supply context-specific parameters during tests.
     */
diff --git a/labs/elb/src/main/java/org/jclouds/elb/loadbalancer/strategy/ELBListLoadBalancersStrategy.java b/labs/elb/src/main/java/org/jclouds/elb/loadbalancer/strategy/ELBListLoadBalancersStrategy.java
index 65dc261..b23916e 100644
--- a/labs/elb/src/main/java/org/jclouds/elb/loadbalancer/strategy/ELBListLoadBalancersStrategy.java
+++ b/labs/elb/src/main/java/org/jclouds/elb/loadbalancer/strategy/ELBListLoadBalancersStrategy.java
@@ -74,14 +74,14 @@
    }
 
    @Override
-   public Iterable<? extends LoadBalancerMetadata> listLoadBalancers() {
+   public Iterable<LoadBalancerMetadata> listLoadBalancers() {
       Iterable<? extends LoadBalancer> loadBalancers;
       Set<String> regions = this.regions.get();
       if (regions.size() > 0)
-         loadBalancers = concat(transformParallel(regions, new Function<String, Future<Set<? extends LoadBalancer>>>() {
+         loadBalancers = concat(transformParallel(regions, new Function<String, Future<? extends Set<? extends LoadBalancer>>>() {
 
             @Override
-            public ListenableFuture<Set<? extends LoadBalancer>> apply(String from) {
+            public ListenableFuture<? extends Set<? extends LoadBalancer>> apply(String from) {
                return aclient.describeLoadBalancersInRegion(from);
             }
 
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapter.java b/labs/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapter.java
index 1fc9e28..386b2c4 100644
--- a/labs/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapter.java
+++ b/labs/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapter.java
@@ -62,6 +62,7 @@
 import org.jclouds.location.predicates.LocationPredicates;
 import org.jclouds.logging.Logger;
 import org.jclouds.predicates.RetryablePredicate;
+import org.jclouds.util.Iterables2;
 
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
@@ -196,13 +197,13 @@
 
    @Override
    public Iterable<ServerDetails> listNodes() {
-      return transformParallel(client.getServerClient().listServers(), new Function<Server, Future<ServerDetails>>() {
+      return Iterables2.concreteCopy(transformParallel(client.getServerClient().listServers(), new Function<Server, Future<? extends ServerDetails>>() {
          @Override
          public Future<ServerDetails> apply(Server from) {
             return aclient.getServerClient().getServerDetails(from.getId());
          }
 
-      }, userThreads, null, logger, "server details");
+      }, userThreads, null, logger, "server details"));
    }
 
    @Override
diff --git a/labs/virtualbox/pom.xml b/labs/virtualbox/pom.xml
index 1d00179..fd78a46 100644
--- a/labs/virtualbox/pom.xml
+++ b/labs/virtualbox/pom.xml
@@ -39,7 +39,7 @@
     <test.virtualbox.build-version>4.1.8r75467</test.virtualbox.build-version>
     <test.virtualbox.identity>administrator</test.virtualbox.identity>
     <test.virtualbox.credential>12345</test.virtualbox.credential>
-    <test.virtualbox.image-id>default-ubuntu-11.04-i386</test.virtualbox.image-id>
+    <test.virtualbox.image-id>test-ubuntu-11.10-i386</test.virtualbox.image-id>
     <test.virtualbox.image.login-user>toor:password</test.virtualbox.image.login-user>
     <test.virtualbox.image.authenticate-sudo>true</test.virtualbox.image.authenticate-sudo>
   </properties>
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapter.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapter.java
index eb0a889..e2e1d21 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapter.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapter.java
@@ -27,12 +27,15 @@
 import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_PREFIX;
 
 import java.util.Map;
+import java.util.Set;
 
 import javax.annotation.Resource;
 import javax.inject.Inject;
 import javax.inject.Named;
 
 import org.jclouds.compute.ComputeServiceAdapter;
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.HardwareBuilder;
 import org.jclouds.compute.domain.Image;
 import org.jclouds.compute.domain.Template;
 import org.jclouds.compute.reference.ComputeServiceConstants;
@@ -58,6 +61,7 @@
 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.Singleton;
 
 /**
@@ -67,25 +71,28 @@
  * @author Mattias Holmqvist, Andrea Turli, David Alves
  */
 @Singleton
-public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IMachine, IMachine, Image, Location> {
+public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IMachine, Hardware, Image, Location> {
 
    @Resource
    @Named(ComputeServiceConstants.COMPUTE_LOGGER)
    protected Logger logger = Logger.NULL;
-   
+
    private final Supplier<VirtualBoxManager> manager;
-   private final Map<Image, YamlImage> images;
+   private final Map<Image, YamlImage> imagesToYamlImages;
    private final LoadingCache<Image, Master> mastersLoader;
    private final Function<NodeSpec, NodeAndInitialCredentials<IMachine>> cloneCreator;
+   private final Function<IMachine, Image> imachineToImage;
 
    @Inject
    public VirtualBoxComputeServiceAdapter(Supplier<VirtualBoxManager> manager,
             Supplier<Map<Image, YamlImage>> imagesMapper, LoadingCache<Image, Master> mastersLoader,
-            Function<NodeSpec, NodeAndInitialCredentials<IMachine>> cloneCreator) {
+            Function<NodeSpec, NodeAndInitialCredentials<IMachine>> cloneCreator,
+            Function<IMachine, Image> imachineToImage) {
       this.manager = checkNotNull(manager, "manager");
-      this.images = imagesMapper.get();
+      this.imagesToYamlImages = imagesMapper.get();
       this.mastersLoader = mastersLoader;
       this.cloneCreator = cloneCreator;
+      this.imachineToImage = imachineToImage;
    }
 
    @Override
@@ -97,7 +104,7 @@
          checkState(!name.contains(VIRTUALBOX_NODE_NAME_SEPARATOR), "node names cannot contain \""
                   + VIRTUALBOX_NODE_NAME_SEPARATOR + "\"");
          Master master = mastersLoader.get(template.getImage());
-         checkState(master != null, "could not find a master for image: "+template.getClass());
+         checkState(master != null, "could not find a master for image: " + template.getImage());
          NodeSpec nodeSpec = NodeSpec.builder().master(master).name(name).tag(tag).template(template).build();
          return cloneCreator.apply(nodeSpec);
       } catch (Exception e) {
@@ -116,13 +123,39 @@
    }
 
    @Override
-   public Iterable<IMachine> listHardwareProfiles() {
-      return imageMachines();
+   public Iterable<Hardware> listHardwareProfiles() {
+      Set<Hardware> hardware = Sets.newLinkedHashSet();
+      hardware.add(new HardwareBuilder().ids("t1.micro").hypervisor("VirtualBox").name("t1.micro").ram(512).build());
+      hardware.add(new HardwareBuilder().ids("m1.small").hypervisor("VirtualBox").name("m1.small").ram(1024).build());
+      hardware.add(new HardwareBuilder().ids("m1.medium").hypervisor("VirtualBox").name("m1.medium").ram(3840).build());
+      hardware.add(new HardwareBuilder().ids("m1.large").hypervisor("VirtualBox").name("m1.large").ram(7680).build());
+      return hardware;
    }
 
    @Override
    public Iterable<Image> listImages() {
-      return images.keySet();
+      // the set of image vm names that were (or could be) built from the yaml file
+      final Set<String> imagesFromYamlNames = Sets.newHashSet(Iterables.transform(imagesToYamlImages.keySet(),
+               new Function<Image, String>() {
+                  @Override
+                  public String apply(Image input) {
+                     return VIRTUALBOX_IMAGE_PREFIX + input.getId();
+                  }
+
+               }));
+
+      // IMachines that were not built from the yaml file transformed to Images
+      Set<Image> imagesFromCloning = Sets.newHashSet(Iterables.transform(
+               Iterables.filter(imageMachines(), new Predicate<IMachine>() {
+                  @Override
+                  public boolean apply(IMachine input) {
+                     return !imagesFromYamlNames.contains(input.getName());
+                  }
+               }), imachineToImage));
+
+      // final set of images are those from yaml and those from vbox that were not a transformation
+      // of the yaml ones
+      return Sets.union(imagesToYamlImages.keySet(), imagesFromCloning);
    }
 
    private Iterable<IMachine> imageMachines() {
@@ -147,7 +180,7 @@
       try {
          return manager.get().getVBox().findMachine(vmName);
       } catch (VBoxException e) {
-         if (e.getMessage().contains("Could not find a registered machine named")){
+         if (e.getMessage().contains("Could not find a registered machine named")) {
             return null;
          }
          throw Throwables.propagate(e);
@@ -202,7 +235,7 @@
 
    private void powerDownMachine(IMachine machine) {
       try {
-         if (machine.getState() == MachineState.PoweredOff){
+         if (machine.getState() == MachineState.PoweredOff) {
             logger.debug("vm was already powered down: ", machine.getId());
             return;
          }
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxImageExtension.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxImageExtension.java
new file mode 100644
index 0000000..3b85954
--- /dev/null
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxImageExtension.java
@@ -0,0 +1,162 @@
+/**
+ * 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.compute;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_DEFAULT_DIR;
+import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX;
+import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_WORKINGDIR;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.compute.ComputeServiceAdapter;
+import org.jclouds.compute.ImageExtension;
+import org.jclouds.compute.domain.CloneImageTemplate;
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.ImageTemplate;
+import org.jclouds.compute.domain.ImageTemplateBuilder;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.domain.Location;
+import org.jclouds.logging.Logger;
+import org.jclouds.virtualbox.functions.IMachineToVmSpec;
+import org.jclouds.virtualbox.functions.TakeSnapshotIfNotAlreadyAttached;
+import org.jclouds.virtualbox.functions.admin.UnregisterMachineIfExistsAndDeleteItsMedia;
+import org.jclouds.virtualbox.util.MachineUtils;
+import org.virtualbox_4_1.CloneMode;
+import org.virtualbox_4_1.CloneOptions;
+import org.virtualbox_4_1.IMachine;
+import org.virtualbox_4_1.IProgress;
+import org.virtualbox_4_1.ISnapshot;
+import org.virtualbox_4_1.VirtualBoxManager;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.collect.Iterables;
+
+@Singleton
+public class VirtualBoxImageExtension implements ImageExtension {
+
+   @Resource
+   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+   private Logger logger = Logger.NULL;
+   private ComputeServiceAdapter<IMachine, Hardware, Image, Location> vboxAdapter;
+   private Function<IMachine, NodeMetadata> machineToNode;
+   private Supplier<VirtualBoxManager> manager;
+   private String workingDir;
+   private boolean isLinkedClone = true;
+   private Function<IMachine, Image> imachineToImage;
+   private MachineUtils machineUtils;
+
+   @Inject
+   public VirtualBoxImageExtension(ComputeServiceAdapter<IMachine, Hardware, Image, Location> vboxAdapter,
+            Function<IMachine, NodeMetadata> machineToNode, Supplier<VirtualBoxManager> manager,
+            @Named(VIRTUALBOX_WORKINGDIR) String workingDir, Function<IMachine, Image> imachineToImage,
+            MachineUtils machineUtils) {
+      this.vboxAdapter = vboxAdapter;
+      this.machineToNode = machineToNode;
+      this.manager = manager;
+      this.workingDir = workingDir == null ? VIRTUALBOX_DEFAULT_DIR : workingDir;
+      this.imachineToImage = imachineToImage;
+      this.machineUtils = machineUtils;
+   }
+
+   @Override
+   public ImageTemplate buildImageTemplateFromNode(String name, final String id) {
+      Optional<NodeMetadata> sourceNode = getNodeById(id);
+      checkState(sourceNode.isPresent(), " there is no node with id " + id);
+      String vmName = VIRTUALBOX_IMAGE_PREFIX + name;
+
+      IMachine vm = null;
+      try {
+         vm = manager.get().getVBox().findMachine(vmName);
+      } catch (Exception e) {
+      }
+      checkState(vm == null, " a machine exists with name: " + vmName);
+      return new ImageTemplateBuilder.CloneImageTemplateBuilder().name(vmName).nodeId(id).build();
+   }
+
+   @Override
+   public Image createImage(ImageTemplate template) {
+      checkState(template instanceof CloneImageTemplate, " vbox image extension only supports cloning for the moment.");
+      CloneImageTemplate cloneTemplate = CloneImageTemplate.class.cast(template);
+
+      IMachine source = manager.get().getVBox().findMachine(cloneTemplate.getSourceNodeId());
+
+      String settingsFile = manager.get().getVBox().composeMachineFilename(template.getName(), workingDir);
+      IMachine clonedMachine = manager.get().getVBox()
+               .createMachine(settingsFile, template.getName(), source.getOSTypeId(), template.getName(), true);
+
+      List<CloneOptions> options = new ArrayList<CloneOptions>();
+      if (isLinkedClone)
+         options.add(CloneOptions.Link);
+
+      // TODO snapshot name
+      ISnapshot currentSnapshot = new TakeSnapshotIfNotAlreadyAttached(manager, "pre-image-spawn", "before spawning "
+               + template.getName(), logger).apply(source);
+
+      checkNotNull(currentSnapshot);
+
+      // clone
+      IProgress progress = currentSnapshot.getMachine().cloneTo(clonedMachine, CloneMode.MachineState, options);
+      progress.waitForCompletion(-1);
+
+      logger.debug(String.format("Machine %s is cloned correctly", clonedMachine.getName()));
+
+      // registering
+      manager.get().getVBox().registerMachine(clonedMachine);
+
+      return imachineToImage.apply(clonedMachine);
+   }
+
+   @Override
+   public boolean deleteImage(String id) {
+      try {
+         IMachine machine = manager.get().getVBox().findMachine(VIRTUALBOX_IMAGE_PREFIX + id);
+         machineUtils.applyForMachine(machine.getId(), new UnregisterMachineIfExistsAndDeleteItsMedia(
+                  new IMachineToVmSpec().apply(machine)));
+      } catch (Exception e) {
+         logger.error(e, "Could not delete machine with id %s ", id);
+         return false;
+      }
+      return true;
+   }
+
+   private Optional<NodeMetadata> getNodeById(final String id) {
+      return Iterables.tryFind(Iterables.transform(vboxAdapter.listNodes(), machineToNode),
+               new Predicate<NodeMetadata>() {
+                  @Override
+                  public boolean apply(NodeMetadata input) {
+                     return input.getId().equals(id);
+                  }
+               });
+   }
+
+}
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxComputeServiceContextModule.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxComputeServiceContextModule.java
index 55160e8..120c862 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxComputeServiceContextModule.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxComputeServiceContextModule.java
@@ -40,8 +40,9 @@
 import org.jclouds.byon.functions.NodeToNodeMetadata;
 import org.jclouds.byon.suppliers.SupplyFromProviderURIOrNodesProperty;
 import org.jclouds.compute.ComputeServiceAdapter;
-import org.jclouds.compute.ComputeServiceContext;
 import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials;
+import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.compute.ImageExtension;
 import org.jclouds.compute.config.ComputeServiceAdapterContextModule;
 import org.jclouds.compute.domain.Hardware;
 import org.jclouds.compute.domain.HardwareBuilder;
@@ -58,6 +59,7 @@
 import org.jclouds.sshj.config.SshjSshClientModule;
 import org.jclouds.virtualbox.Host;
 import org.jclouds.virtualbox.compute.VirtualBoxComputeServiceAdapter;
+import org.jclouds.virtualbox.compute.VirtualBoxImageExtension;
 import org.jclouds.virtualbox.domain.CloneSpec;
 import org.jclouds.virtualbox.domain.ExecutionType;
 import org.jclouds.virtualbox.domain.IsoSpec;
@@ -88,6 +90,7 @@
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Function;
 import com.google.common.base.Functions;
+import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;
 import com.google.common.base.Suppliers;
@@ -105,17 +108,19 @@
  */
 @SuppressWarnings("unchecked")
 public class VirtualBoxComputeServiceContextModule extends
-         ComputeServiceAdapterContextModule<IMachine, IMachine, Image, Location> {
+         ComputeServiceAdapterContextModule<IMachine, Hardware, Image, Location> {
 
    @Override
    protected void configure() {
       super.configure();
-      bind(new TypeLiteral<ComputeServiceAdapter<IMachine, IMachine, Image, Location>>() {
+      bind(new TypeLiteral<ComputeServiceAdapter<IMachine, Hardware, Image, Location>>() {
       }).to(VirtualBoxComputeServiceAdapter.class);
       bind(new TypeLiteral<Function<IMachine, NodeMetadata>>() {
       }).to(IMachineToNodeMetadata.class);
       bind(new TypeLiteral<Function<Location, Location>>() {
       }).to((Class) IdentityFunction.class);
+      bind(new TypeLiteral<Function<Hardware, Hardware>>() {
+      }).to((Class) IdentityFunction.class);
       bind(new TypeLiteral<Function<Image, Image>>() {
       }).to((Class) IdentityFunction.class);
       bind(new TypeLiteral<Function<IMachine, Hardware>>() {
@@ -139,6 +144,10 @@
       bind(new TypeLiteral<LoadingCache<Image, Master>>() {
       }).to(MastersLoadingCache.class);
 
+      // the vbox image extension
+      bind(new TypeLiteral<ImageExtension>() {
+      }).to(VirtualBoxImageExtension.class);
+
       // the master creating function
       bind(new TypeLiteral<Function<MasterSpec, IMachine>>() {
       }).to((Class) CreateAndInstallVm.class);
@@ -166,10 +175,9 @@
    @Host
    @Singleton
    protected ComputeServiceContext provideHostController() {
-      return ContextBuilder.newBuilder(new BYONApiMetadata())
-            .credentials("", "")
-            .modules(ImmutableSet.<Module> of(new SLF4JLoggingModule(), new SshjSshClientModule()))
-            .build(ComputeServiceContext.class);
+      return ContextBuilder.newBuilder(new BYONApiMetadata()).credentials("", "")
+               .modules(ImmutableSet.<Module> of(new SLF4JLoggingModule(), new SshjSshClientModule()))
+               .build(ComputeServiceContext.class);
    }
 
    @Provides
@@ -203,18 +211,6 @@
    }
 
    @Override
-   protected Supplier provideHardware(ComputeServiceAdapter<IMachine, IMachine, Image, Location> adapter,
-            Function<IMachine, Hardware> transformer) {
-      // since no vms might be available we need to list images
-      Iterable<Image> images = adapter.listImages();
-      Set<Hardware> hardware = Sets.newHashSet();
-      for (Image image : images) {
-         hardware.add(new HardwareBuilder().ids(image.getId()).hypervisor("VirtualBox").name(image.getName()).build());
-      }
-      return Suppliers.ofInstance(hardware);
-   }
-
-   @Override
    protected TemplateBuilder provideTemplate(Injector injector, TemplateBuilder template) {
       return template.osFamily(VIRTUALBOX_DEFAULT_IMAGE_OS).osVersionMatches(VIRTUALBOX_DEFAULT_IMAGE_VERSION)
                .osArchMatches(VIRTUALBOX_DEFAULT_IMAGE_ARCH);
@@ -233,6 +229,11 @@
       }), nodes);
    }
 
+   @Override
+   protected Optional<ImageExtension> provideImageExtension(Injector i) {
+      return Optional.of(i.getInstance(ImageExtension.class));
+   }
+
    @VisibleForTesting
    public static final Map<MachineState, NodeState> machineToNodeState = ImmutableMap
             .<MachineState, NodeState> builder().put(MachineState.Running, NodeState.RUNNING)
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIMachineIfNotAlreadyExists.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIMachineIfNotAlreadyExists.java
index 0fb2f36..46521df 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIMachineIfNotAlreadyExists.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIMachineIfNotAlreadyExists.java
@@ -99,13 +99,13 @@
                .getVBox()
                .createMachine(settingsFile, vmSpec.getVmName(), vmSpec.getOsTypeId(), vmSpec.getVmId(),
                         vmSpec.isForceOverwrite());
-      
+
       List<CloneOptions> options = new ArrayList<CloneOptions>();
       if (isLinkedClone)
          options.add(CloneOptions.Link);
 
       // TODO snapshot name
-      ISnapshot currentSnapshot = new TakeSnapshotIfNotAlreadyAttached(manager, "snapshotName", "snapshotDesc")
+      ISnapshot currentSnapshot = new TakeSnapshotIfNotAlreadyAttached(manager, "snapshotName", "snapshotDesc", logger)
                .apply(master);
 
       // clone
@@ -114,6 +114,9 @@
       progress.waitForCompletion(-1);
       logger.debug(String.format("Machine %s is cloned correctly", clonedMachine.getName()));
 
+      // memory may not be the same as the master vm
+      clonedMachine.setMemorySize(cloneSpec.getVmSpec().getMemory());
+
       // registering
       manager.get().getVBox().registerMachine(clonedMachine);
 
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToImage.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToImage.java
index 36805d7..dab6dac 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToImage.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToImage.java
@@ -33,6 +33,7 @@
 import org.jclouds.compute.domain.OperatingSystem;
 import org.jclouds.compute.domain.OsFamily;
 import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.virtualbox.config.VirtualBoxConstants;
 import org.virtualbox_4_1.IGuestOSType;
 import org.virtualbox_4_1.IMachine;
 import org.virtualbox_4_1.VirtualBoxManager;
@@ -63,7 +64,9 @@
       OperatingSystem os = OperatingSystem.builder().description(guestOSType.getDescription()).family(family)
                .version(version).is64Bit(guestOSType.getIs64Bit()).build();
 
-      return new ImageBuilder().id("" + from.getId()).name(from.getName()).description(from.getDescription())
+      return new ImageBuilder()
+               .id(from.getName().substring(VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX.length(),
+                        from.getName().length())).name(from.getName()).description(from.getDescription())
                .operatingSystem(os).build();
    }
 
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadata.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadata.java
index 9e99d8c..5379d38 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadata.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadata.java
@@ -95,8 +95,6 @@
          nodeState = NodeState.UNRECOGNIZED;
       nodeMetadataBuilder.state(nodeState);
 
-      logger.debug("Setting virtualbox node to: " + nodeState + " from machine state: " + vmState);
-
       /*
       // nat adapter
       INetworkAdapter natAdapter = vm.getNetworkAdapter(0l);
@@ -139,7 +137,6 @@
    
    private NodeMetadataBuilder getIpAddresses(IMachine vm, NodeMetadataBuilder nodeMetadataBuilder) {
       List<String> publicIpAddresses = Lists.newArrayList();
-      List<String> privateIpAddresses = Lists.newArrayList();
 
       for(long slot = 0; slot < 4; slot ++) {
          INetworkAdapter adapter = vm.getNetworkAdapter(slot);
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersLoadingCache.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersLoadingCache.java
index 5aa6682..e54c011 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersLoadingCache.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersLoadingCache.java
@@ -141,14 +141,51 @@
          return masters.get(key.getId());
       }
 
-      // the yaml image
-      YamlImage currentImage = imageMapping.get(key.getId());
-
-      checkNotNull(currentImage, "could not find yaml image for image: " + key);
-      
-      checkState(!currentImage.id.contains(VIRTUALBOX_NODE_NAME_SEPARATOR), "master image names cannot contain \""
+      checkState(!key.getId().contains(VIRTUALBOX_NODE_NAME_SEPARATOR), "master image names cannot contain \""
                + VIRTUALBOX_NODE_NAME_SEPARATOR + "\"");
 
+      String vmName = VIRTUALBOX_IMAGE_PREFIX + key.getId();
+
+      IMachine masterMachine;
+
+      Master master;
+
+      // ready the preseed file server
+      PreseedCfgServer server = new PreseedCfgServer();
+      try {
+         // try and find a master machine in vbox
+         masterMachine = manager.get().getVBox().findMachine(vmName);
+         master = Master.builder().machine(masterMachine).build();
+
+      } catch (VBoxException e) {
+         if (machineNotFoundException(e)) {
+            // machine was not found try to build one from a yaml file
+            YamlImage currentImage = imageMapping.get(key.getId());
+
+            checkNotNull(currentImage);
+
+            server.start(preconfigurationUrl, currentImage.preseed_cfg);
+
+            MasterSpec masterSpec = buildMasterSpecFromYaml(currentImage, vmName);
+
+            // create the master machine if it can't be found
+            masterMachine = masterCreatorAndInstaller.apply(masterSpec);
+
+            // build the master
+            master = Master.builder().machine(masterMachine).spec(masterSpec).build();
+         } else {
+            throw e;
+         }
+      } finally {
+         server.stop();
+      }
+
+      masters.put(key.getId(), master);
+      return master;
+   }
+
+   private MasterSpec buildMasterSpecFromYaml(YamlImage currentImage, String vmName) throws ExecutionException {
+
       String guestAdditionsFileName = String.format("VBoxGuestAdditions_%s.iso", version);
       String guestAdditionsIso = String.format("%s/%s", isosDir, guestAdditionsFileName);
       String guestAdditionsUri = "http://download.virtualbox.org/virtualbox/" + version + "/" + guestAdditionsFileName;
@@ -160,8 +197,6 @@
       // check if the iso is here, download if not
       String localIsoUrl = getFilePathOrDownload(currentImage.iso);
 
-      String vmName = VIRTUALBOX_IMAGE_PREFIX + currentImage.id;
-
       String adminDisk = workingDir + File.separator + vmName + ".vdi";
 
       HardDisk hardDisk = HardDisk.builder().diskpath(adminDisk).autoDelete(true).controllerPort(0).deviceSlot(1)
@@ -174,46 +209,19 @@
                .controller(ideController).forceOverwrite(true).cleanUpMode(CleanupMode.Full).build();
 
       NetworkAdapter networkAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT)
-               .tcpRedirectRule("127.0.0.1", MASTER_PORT , "", 22).build();
+               .tcpRedirectRule("127.0.0.1", MASTER_PORT, "", 22).build();
 
       NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter)
                .slot(0L).build();
-      
+
       NetworkSpec networkSpec = NetworkSpec.builder().addNIC(networkInterfaceCard).build();
 
-      MasterSpec masterSpec = MasterSpec
+      return MasterSpec
                .builder()
                .vm(vmSpecification)
                .iso(IsoSpec.builder().sourcePath(localIsoUrl)
                         .installationScript(installationKeySequence.replace("HOSTNAME", vmSpecification.getVmName()))
                         .build()).network(networkSpec).build();
-
-      IMachine masterMachine;
-
-      
-      // ready the preseed file server
-      PreseedCfgServer server = new PreseedCfgServer();
-      try {
-         // try and find a master machine in vbox
-         masterMachine = manager.get().getVBox().findMachine(vmName);
-      } catch (VBoxException e) {
-         if (machineNotFoundException(e)) {
-            server.start(preconfigurationUrl,currentImage.preseed_cfg);
-            // create the master machine if it can't be found
-            masterMachine = masterCreatorAndInstaller.apply(masterSpec);
-         } else {
-            throw e;
-         }
-      } finally {
-         server.stop();
-      }
-      
-
-      Master master = Master.builder().machine(masterMachine).spec(masterSpec).build();
-
-      masters.put(key.getId(), master);
-
-      return master;
    }
 
    @Override
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/NodeCreator.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/NodeCreator.java
index a7f2ff9..a70f4ef 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/NodeCreator.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/NodeCreator.java
@@ -118,12 +118,18 @@
          progress.waitForCompletion(-1);
          session.unlockMachine();
       }
-      String masterNameWithoutPrefix = master.getSpec().getVmSpec().getVmName().replace(VIRTUALBOX_IMAGE_PREFIX, "");
+      String masterNameWithoutPrefix = master.getMachine().getName().replace(VIRTUALBOX_IMAGE_PREFIX, "");
 
       String cloneName = VIRTUALBOX_NODE_PREFIX + masterNameWithoutPrefix + VIRTUALBOX_NODE_NAME_SEPARATOR
                + nodeSpec.getTag() + VIRTUALBOX_NODE_NAME_SEPARATOR + nodeSpec.getName();
 
-      VmSpec cloneVmSpec = VmSpec.builder().id(cloneName).name(cloneName).memoryMB(512).cleanUpMode(CleanupMode.Full)
+      int ram = 512;
+      if (nodeSpec.getTemplate() != null && nodeSpec.getTemplate().getHardware() != null
+               && nodeSpec.getTemplate().getHardware().getRam() > 0) {
+         ram = nodeSpec.getTemplate().getHardware().getRam();
+      }
+      
+      VmSpec cloneVmSpec = VmSpec.builder().id(cloneName).name(cloneName).memoryMB(ram).cleanUpMode(CleanupMode.Full)
                .forceOverwrite(true).build();
 
       // CASE NAT + HOST-ONLY
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/TakeSnapshotIfNotAlreadyAttached.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/TakeSnapshotIfNotAlreadyAttached.java
index e496cb5..830c23e 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/TakeSnapshotIfNotAlreadyAttached.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/TakeSnapshotIfNotAlreadyAttached.java
@@ -20,15 +20,13 @@
 package org.jclouds.virtualbox.functions;
 
 import javax.annotation.Nullable;
-import javax.annotation.Resource;
-import javax.inject.Named;
 
-import org.jclouds.compute.reference.ComputeServiceConstants;
 import org.jclouds.logging.Logger;
 import org.virtualbox_4_1.IMachine;
 import org.virtualbox_4_1.IProgress;
 import org.virtualbox_4_1.ISession;
 import org.virtualbox_4_1.ISnapshot;
+import org.virtualbox_4_1.MachineState;
 import org.virtualbox_4_1.VirtualBoxManager;
 
 import com.google.common.base.Function;
@@ -40,55 +38,80 @@
  */
 public class TakeSnapshotIfNotAlreadyAttached implements Function<IMachine, ISnapshot> {
 
-   @Resource
-   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
-   protected Logger logger = Logger.NULL;
-
    private Supplier<VirtualBoxManager> manager;
    private String snapshotName;
    private String snapshotDesc;
+   private Logger logger;
 
-   public TakeSnapshotIfNotAlreadyAttached(Supplier<VirtualBoxManager> manager, String snapshotName, String snapshotDesc) {
+   public TakeSnapshotIfNotAlreadyAttached(Supplier<VirtualBoxManager> manager, String snapshotName,
+            String snapshotDesc, Logger logger) {
       this.manager = manager;
       this.snapshotName = snapshotName;
       this.snapshotDesc = snapshotDesc;
+      this.logger = logger;
    }
 
    @Override
    public ISnapshot apply(@Nullable IMachine machine) {
       // Snapshot a machine
       ISession session = null;
-      if (machine.getCurrentSnapshot() == null) {
-         int retries = 10;
-         while (true) {
-            try {
-               session = manager.get().openMachineSession(machine);
-               IProgress progress = session.getConsole().takeSnapshot(snapshotName, snapshotDesc);
-               progress.waitForCompletion(-1);
-               logger.debug("Snapshot %s (description: %s) taken from %s", snapshotName, snapshotDesc,
-                        machine.getName());
-               break;
-            } catch (Exception e) {
-               if (e.getMessage().contains("VirtualBox error: The object is not ready")) {
-                  retries--;
-                  if (retries == 0) {
-                     logger.error(e,
-                              "Problem creating snapshot (too many retries) %s (descripton: %s) from machine %s",
-                              snapshotName, snapshotDesc, machine.getName());
-                     throw Throwables.propagate(e);
+      ISnapshot snap = machine.getCurrentSnapshot();
+
+      if (snap == null) {
+         try {
+            session = manager.get().openMachineSession(machine);
+            logger.debug("No snapshot available taking new one: %s (description: %s) taken from %s", snapshotName,
+                     snapshotDesc, machine.getName());
+            int retries = 10;
+            while (true) {
+               try {
+
+                  // running machines need to be pause before a snapshot can be taken
+                  // due to a vbox bug see https://www.virtualbox.org/ticket/9255
+                  boolean paused = false;
+                  if (machine.getState() == MachineState.Running) {
+                     session.getConsole().pause();
+                     paused = true;
                   }
-               }
-               logger.error(e, "Problem creating snapshot %s (descripton: %s) from machine %s", snapshotName,
-                        snapshotDesc, machine.getName());
-               throw Throwables.propagate(e);
-            } finally {
-               if (session != null) {
-                  session.unlockMachine();
+
+                  IProgress progress = session.getConsole().takeSnapshot(snapshotName, snapshotDesc);
+                  progress.waitForCompletion(-1);
+
+                  if (paused) {
+                     session.getConsole().resume();
+                  }
+
+                  snap = machine.getCurrentSnapshot();
+                  logger.debug("Snapshot %s (description: %s) taken from %s", snapshotName, snapshotDesc,
+                           machine.getName());
+                  break;
+               } catch (Exception e) {
+                  if (e.getMessage().contains("VirtualBox error: The object is not ready")
+                           || e.getMessage().contains("This machine does not have any snapshots")) {
+                     retries--;
+                     if (retries == 0) {
+                        logger.error(e,
+                                 "Problem creating snapshot (too many retries) %s (descripton: %s) from machine %s",
+                                 snapshotName, snapshotDesc, machine.getName());
+                        throw Throwables.propagate(e);
+                     }
+                     Thread.sleep(1000L);
+                     continue;
+                  }
+                  logger.error(e, "Problem creating snapshot %s (descripton: %s) from machine %s", snapshotName,
+                           snapshotDesc, machine.getName());
+                  throw Throwables.propagate(e);
                }
             }
+         } catch (Exception e) {
+            Throwables.propagate(e);
+         } finally {
+            if (session != null) {
+               manager.get().closeMachineSession(session);
+            }
          }
-      }
-      return machine.getCurrentSnapshot();
-   }
 
+      }
+      return snap;
+   }
 }
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunning.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunning.java
index dda2cb3..8c231f1 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunning.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunning.java
@@ -26,7 +26,6 @@
 import java.net.URI;
 
 import javax.annotation.Nullable;
-import javax.annotation.PostConstruct;
 import javax.annotation.Resource;
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -74,10 +73,10 @@
       this.host = checkNotNull(host, "host");
       this.providerSupplier = checkNotNull(providerSupplier, "endpoint to virtualbox websrvd is needed");
       this.managerForNode = checkNotNull(managerForNode, "managerForNode");
+      start();
    }
 
-   @PostConstruct
-   public void start() {
+   public synchronized void start() {
       URI provider = providerSupplier.get();
       if (!socketTester.apply(new IPSocket(provider.getHost(), provider.getPort()))) {
          logger.debug("disabling password access");
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndDeleteItsMedia.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndDeleteItsMedia.java
index ce02937..bc3dde9 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndDeleteItsMedia.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndDeleteItsMedia.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 /*
-U * Licensed to jclouds, Inc. (jclouds) under one or more
+ U * 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
@@ -93,8 +93,8 @@
          }
       }
 
-      List<IMedium> filteredMediaToBeDeleted = Lists.newArrayList(transform(filter(mediaToBeDeleted,
-               new AutoDeleteHardDiskPredicate(vmSpec)), new DeleteChildrenOfMedium()));
+      List<IMedium> filteredMediaToBeDeleted = Lists.newArrayList(transform(
+               filter(mediaToBeDeleted, new AutoDeleteHardDiskPredicate(vmSpec)), new DeleteChildrenOfMedium()));
 
       if (!filteredMediaToBeDeleted.isEmpty()) {
          try {
@@ -105,7 +105,7 @@
             Throwables.propagate(e);
          }
       }
-      
+
       return null;
    }
 
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndForceDeleteItsMedia.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndForceDeleteItsMedia.java
index b4d2e7c..db2761c 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndForceDeleteItsMedia.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndForceDeleteItsMedia.java
@@ -105,8 +105,17 @@
          checkNotNull(medium.getChildren());
          if (medium.getDeviceType().equals(DeviceType.HardDisk)) {
             for (IMedium child : medium.getChildren()) {
-               IProgress deletion = child.deleteStorage();
-               deletion.waitForCompletion(-1);
+               try {
+                  IProgress deletion = child.deleteStorage();
+                  deletion.waitForCompletion(-1);
+               } catch (Exception e) {
+                  // work around media that are still attached to other vm's. this can happen when a
+                  // running node is used to create a new image and then an attempt at deleting it
+                  // is made
+                  if (e.getMessage().contains("is still attached to the following")) {
+                     logger.warn("Media could not be deleted. Ignoring... [Message %s]", e.getMessage());
+                  }
+               }
             }
          }
          return medium;
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/BaseVirtualBoxClientLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/BaseVirtualBoxClientLiveTest.java
index fe6cf54..33477e5 100644
--- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/BaseVirtualBoxClientLiveTest.java
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/BaseVirtualBoxClientLiveTest.java
@@ -39,6 +39,7 @@
 import org.jclouds.concurrent.config.ExecutorServiceModule;
 import org.jclouds.config.ValueOfConfigurationKeyOrNull;
 import org.jclouds.rest.annotations.BuildVersion;
+import org.jclouds.sshj.config.SshjSshClientModule;
 import org.jclouds.virtualbox.config.VirtualBoxConstants;
 import org.jclouds.virtualbox.domain.HardDisk;
 import org.jclouds.virtualbox.domain.IsoSpec;
@@ -217,6 +218,11 @@
                "/default-images.yaml")).get();
       return images.get(Iterables.getOnlyElement(Iterables.filter(images.keySet(), new DefaultImagePredicate())));
    }
+   
+   @Override
+   protected Module getSshModule() {
+      return new SshjSshClientModule();
+   }
 
    @AfterClass(groups = "live")
    protected void tearDown() throws Exception {
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapterLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapterLiveTest.java
index b01067c..525331a 100644
--- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapterLiveTest.java
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapterLiveTest.java
@@ -27,6 +27,7 @@
 
 import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials;
 import org.jclouds.compute.domain.ExecResponse;
+import org.jclouds.compute.domain.Hardware;
 import org.jclouds.compute.domain.Image;
 import org.jclouds.compute.domain.Template;
 import org.jclouds.domain.LoginCredentials;
@@ -76,7 +77,7 @@
 
    @Test
    public void testListHardwareProfiles() {
-      Iterable<IMachine> profiles = adapter.listHardwareProfiles();
+      Iterable<Hardware> profiles = adapter.listHardwareProfiles();
       assertTrue(!Iterables.isEmpty(profiles));
    }
 
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxImageExtensionLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxImageExtensionLiveTest.java
new file mode 100644
index 0000000..c498ce9
--- /dev/null
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxImageExtensionLiveTest.java
@@ -0,0 +1,40 @@
+/**
+ * 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.compute;
+
+import org.jclouds.compute.internal.BaseImageExtensionLiveTest;
+import org.jclouds.sshj.config.SshjSshClientModule;
+import org.testng.annotations.Test;
+
+import com.google.inject.Module;
+
+@Test(groups = "live", singleThreaded = true, testName = "VirtualBoxImageExtensionLiveTest")
+public class VirtualBoxImageExtensionLiveTest extends BaseImageExtensionLiveTest {
+
+   public VirtualBoxImageExtensionLiveTest() {
+      provider = "virtualbox";
+   }
+
+   @Override
+   protected Module getSshModule() {
+      return new SshjSshClientModule();
+   }
+
+}
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java
index d475cd8..45bd5df 100644
--- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java
@@ -20,7 +20,7 @@
 package org.jclouds.virtualbox.functions;
 
 import static com.google.common.base.Preconditions.checkState;
-import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
 import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX;
 import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE;
 
@@ -56,9 +56,7 @@
 import com.google.common.base.CaseFormat;
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
-import com.google.common.base.Splitter;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
@@ -166,15 +164,14 @@
          checkState(sshResponds.apply(client), "timed out waiting for guest %s to be accessible via ssh",
                   machine.getName());
 
-         String vboxVersion = Iterables.get(
-                  Splitter.on('r').split(context.getProviderSpecificContext().getBuildVersion()), 0);
-         assertEquals(vboxVersion,
-                  machineUtils.sharedLockMachineAndApplyToSession(machine.getName(), new Function<ISession, String>() {
-                     @Override
-                     public String apply(ISession session) {
-                        return session.getMachine().getGuestPropertyValue("/VirtualBox/GuestAdd/Version");
-                     }
-                  }));
+         String version = machineUtils.sharedLockMachineAndApplyToSession(machine.getName(), new Function<ISession, String>() {
+            @Override
+            public String apply(ISession session) {
+               return session.getMachine().getGuestPropertyValue("/VirtualBox/GuestAdd/Version");
+            }
+         });
+         
+         assertTrue(version != null && !version.isEmpty());
       } finally {
          for (VmSpec spec : ImmutableSet.of(machineSpec.getVmSpec())) {
             machineController.ensureMachineIsShutdown(spec.getVmName());
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/IMachineToImageTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/IMachineToImageTest.java
index b47f5de..8db2dfb 100644
--- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/IMachineToImageTest.java
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/IMachineToImageTest.java
@@ -34,6 +34,7 @@
 import org.jclouds.compute.reference.ComputeServiceConstants;
 import org.jclouds.json.Json;
 import org.jclouds.json.config.GsonModule;
+import org.jclouds.virtualbox.config.VirtualBoxConstants;
 import org.testng.annotations.Test;
 import org.virtualbox_4_1.IGuestOSType;
 import org.virtualbox_4_1.IMachine;
@@ -48,7 +49,7 @@
 
    Map<OsFamily, Map<String, String>> map = new BaseComputeServiceContextModule() {
    }.provideOsVersionMap(new ComputeServiceConstants.ReferenceData(), Guice.createInjector(new GsonModule())
-         .getInstance(Json.class));
+            .getInstance(Json.class));
 
    @Test
    public void testConvert() throws Exception {
@@ -61,6 +62,7 @@
       expect(vbm.getVBox()).andReturn(vBox).anyTimes();
 
       expect(vm.getOSTypeId()).andReturn("os-type").anyTimes();
+      expect(vm.getName()).andReturn(VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX + "my-vm-id").anyTimes();
       expect(vBox.getGuestOSType(eq("os-type"))).andReturn(guestOsType);
       expect(vm.getDescription()).andReturn("my-ubuntu-machine").anyTimes();
       expect(guestOsType.getDescription()).andReturn(linuxDescription).anyTimes();
@@ -77,6 +79,7 @@
       assertTrue(image.getOperatingSystem().is64Bit());
       assertEquals(image.getOperatingSystem().getFamily(), OsFamily.UBUNTU);
       assertEquals(image.getOperatingSystem().getVersion(), "10.04");
+      assertEquals(image.getId(), "my-vm-id");
 
    }
 
@@ -91,6 +94,7 @@
       String vmDescription = "ubuntu-11.04-server-i386";
       expect(vbm.getVBox()).andReturn(vBox).anyTimes();
 
+      expect(vm.getName()).andReturn(VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX + "my-vm-id").anyTimes();
       expect(vm.getOSTypeId()).andReturn("os-type").anyTimes();
       expect(vBox.getGuestOSType(eq("os-type"))).andReturn(guestOsType);
       expect(vm.getDescription()).andReturn(vmDescription).anyTimes();
@@ -108,6 +112,7 @@
       assertTrue(image.getOperatingSystem().is64Bit());
       assertEquals(image.getOperatingSystem().getFamily(), OsFamily.UBUNTU);
       assertEquals(image.getOperatingSystem().getVersion(), "11.04");
+      assertEquals(image.getId(), "my-vm-id");
 
    }
 
@@ -121,6 +126,7 @@
 
       expect(vbm.getVBox()).andReturn(vBox).anyTimes();
 
+      expect(vm.getName()).andReturn(VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX + "my-vm-id").anyTimes();
       String unknownOsDescription = "SomeOtherOs 2.04";
       expect(vm.getOSTypeId()).andReturn("os-type").anyTimes();
       expect(vm.getDescription()).andReturn("my-unknown-machine").anyTimes();
@@ -136,6 +142,7 @@
 
       assertEquals(image.getOperatingSystem().getDescription(), "SomeOtherOs 2.04");
       assertEquals(image.getOperatingSystem().getVersion(), "");
+      assertEquals(image.getId(), "my-vm-id");
 
    }
 
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/TakeSnapshotIfNotAlreadyAttachedTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/TakeSnapshotIfNotAlreadyAttachedTest.java
index 6b2f3a0..3e3bb58 100644
--- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/TakeSnapshotIfNotAlreadyAttachedTest.java
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/TakeSnapshotIfNotAlreadyAttachedTest.java
@@ -24,6 +24,7 @@
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
 
+import org.jclouds.logging.Logger;
 import org.testng.annotations.Test;
 import org.virtualbox_4_1.IConsole;
 import org.virtualbox_4_1.IMachine;
@@ -31,6 +32,7 @@
 import org.virtualbox_4_1.ISession;
 import org.virtualbox_4_1.ISnapshot;
 import org.virtualbox_4_1.IVirtualBox;
+import org.virtualbox_4_1.MachineState;
 import org.virtualbox_4_1.VirtualBoxManager;
 
 import com.google.common.base.Suppliers;
@@ -55,6 +57,7 @@
       IProgress progress = createNiceMock(IProgress.class);
       ISnapshot snapshot = createNiceMock(ISnapshot.class);
       expect(machine.getCurrentSnapshot()).andReturn(snapshot).anyTimes();
+      expect(machine.getState()).andReturn(MachineState.PoweredOff).anyTimes();
 
       expect(manager.openMachineSession(machine)).andReturn(session);
 
@@ -66,7 +69,7 @@
       session.unlockMachine();
       replay(manager, machine, vBox, session, console, progress);
 
-      new TakeSnapshotIfNotAlreadyAttached(Suppliers.ofInstance(manager), snapshotName, snapshotDesc)
+      new TakeSnapshotIfNotAlreadyAttached(Suppliers.ofInstance(manager), snapshotName, snapshotDesc, Logger.CONSOLE)
             .apply(machine);
 
       verify(machine);
@@ -87,6 +90,7 @@
       expect(progress.getCompleted()).andReturn(true);
       expect(machine.getCurrentSnapshot()).andReturn(null).anyTimes();
       expect(manager.openMachineSession(machine)).andReturn(session);
+      expect(machine.getState()).andReturn(MachineState.PoweredOff).anyTimes();
 
       expect(machine.getName()).andReturn("machine").anyTimes();
       expect(session.getConsole()).andReturn(console);
@@ -96,7 +100,7 @@
       session.unlockMachine();
       replay(manager, machine, vBox, session, console, progress);
 
-      new TakeSnapshotIfNotAlreadyAttached(Suppliers.ofInstance(manager), snapshotName, snapshotDesc)
+      new TakeSnapshotIfNotAlreadyAttached(Suppliers.ofInstance(manager), snapshotName, snapshotDesc, Logger.CONSOLE)
             .apply(machine);
 
       verify(machine);
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunningLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunningLiveTest.java
index 6be7199..be64f61 100644
--- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunningLiveTest.java
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunningLiveTest.java
@@ -21,6 +21,7 @@
 
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
 import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot;
@@ -58,10 +59,9 @@
       String identity = "adminstrator";
       String credential = "12345";
       expect(client.seconds(3)).andReturn(client);
-
-      expect(client.apply(new IPSocket(provider.getHost(), provider.getPort()))).andReturn(true);
-
+      expect(client.apply(new IPSocket(provider.getHost(), provider.getPort()))).andReturn(true).anyTimes();
       manager.connect(provider.toASCIIString(), "", "");
+      expectLastCall().anyTimes();
 
       replay(manager, runScriptOnNodeFactory, client);
 
@@ -87,17 +87,18 @@
       String credential = "12345";
       
       expect(client.seconds(3)).andReturn(client);
-      expect(client.apply(new IPSocket(provider.getHost(), provider.getPort()))).andReturn(false);
+      expect(client.apply(new IPSocket(provider.getHost(), provider.getPort()))).andReturn(false).once().andReturn(true).once();
       expect(
                runScriptOnNodeFactory.create(host, Statements.exec("VBoxManage setproperty websrvauthlibrary null"),
                         runAsRoot(false).wrapInInitScript(false))).andReturn(runScriptOnNode);
       expect(runScriptOnNode.init()).andReturn(runScriptOnNode);
       expect(runScriptOnNode.call()).andReturn(new ExecResponse("", "", 0));
-      expect(client.apply(new IPSocket(provider.getHost(), provider.getPort()))).andReturn(true);
+      
       expect(
                runScriptOnNodeFactory.create(host, Statements.exec("vboxwebsrv -t 10000 -v -b"), runAsRoot(false)
                         .wrapInInitScript(false).blockOnComplete(false).nameTask("vboxwebsrv"))).andReturn(
                runScriptOnNode);
+      
       expect(runScriptOnNode.init()).andReturn(runScriptOnNode);
       expect(runScriptOnNode.call()).andReturn(new ExecResponse("", "", 0));
       
@@ -105,7 +106,7 @@
 
       replay(manager, runScriptOnNodeFactory, runScriptOnNode, client);
       new StartVBoxIfNotAlreadyRunning((Function) Functions.constant(manager), runScriptOnNodeFactory, client,
-               Suppliers.ofInstance(host), Suppliers.ofInstance(provider), identity, credential).start();
+               Suppliers.ofInstance(host), Suppliers.ofInstance(provider), identity, credential);
       verify(manager, runScriptOnNodeFactory, runScriptOnNode, client);
 
    }
diff --git a/labs/virtualbox/src/test/resources/logback.xml b/labs/virtualbox/src/test/resources/logback.xml
index f9b64ed..3a5a73c 100644
--- a/labs/virtualbox/src/test/resources/logback.xml
+++ b/labs/virtualbox/src/test/resources/logback.xml
@@ -39,7 +39,7 @@
     </appender>

 

     <root>

-        <level value="debug" />

+        <level value="DEBUG" />

         <appender-ref ref="CONSOLE" />

     </root>

 

@@ -49,7 +49,7 @@
     </logger>

 

     <logger name="jclouds.wire">

-        <level value="INFO" />

+        <level value="DEBUG" />

         <appender-ref ref="WIREFILE" />

     </logger>

 

diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeService.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeService.java
index d54c7ed..eccd369 100644
--- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeService.java
+++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeService.java
@@ -42,6 +42,7 @@
 import org.jclouds.aws.util.AWSUtils;
 import org.jclouds.collect.Memoized;
 import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.compute.ImageExtension;
 import org.jclouds.compute.RunNodesException;
 import org.jclouds.compute.callables.RunScriptOnNode;
 import org.jclouds.compute.domain.Hardware;
@@ -72,6 +73,7 @@
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Function;
+import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;
 import com.google.common.cache.LoadingCache;
@@ -111,12 +113,13 @@
             @Named("SECURITY") LoadingCache<RegionAndName, String> securityGroupMap,
             @Named("PLACEMENT") LoadingCache<RegionAndName, String> placementGroupMap,
             @Named("DELETED") Predicate<PlacementGroup> placementGroupDeleted,
-            @Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean generateInstanceNames, AWSEC2AsyncClient aclient) {
+            @Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean generateInstanceNames, AWSEC2AsyncClient aclient,
+            Optional<ImageExtension> imageExtension) {
       super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
                runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy,
                stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
                nodeSuspended, initScriptRunnerFactory, runScriptOnNodeFactory, initAdminAccess, persistNodeCredentials,
-               timeouts, executor, ec2Client, credentialsMap, securityGroupMap);
+               timeouts, executor, ec2Client, credentialsMap, securityGroupMap, imageExtension);
       this.ec2Client = ec2Client;
       this.placementGroupMap = placementGroupMap;
       this.placementGroupDeleted = placementGroupDeleted;
diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/strategy/AWSEC2ListNodesStrategy.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/strategy/AWSEC2ListNodesStrategy.java
index 8f09824..240e616 100644
--- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/strategy/AWSEC2ListNodesStrategy.java
+++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/strategy/AWSEC2ListNodesStrategy.java
@@ -69,12 +69,10 @@
    @Override
    protected Iterable<? extends RunningInstance> pollRunningInstances() {
       Iterable<? extends AWSRunningInstance> spots = filter(transform(concat(transformParallel(regions.get(),
-               new Function<String, Future<Set<SpotInstanceRequest>>>() {
-
-                  @SuppressWarnings("unchecked")
+               new Function<String, Future<? extends Set<SpotInstanceRequest>>>() {
                   @Override
-                  public Future<Set<SpotInstanceRequest>> apply(String from) {
-                     return (Future<Set<SpotInstanceRequest>>) client.getSpotInstanceServices()
+                  public Future<? extends Set<SpotInstanceRequest>> apply(String from) {
+                     return client.getSpotInstanceServices()
                               .describeSpotInstanceRequestsInRegion(from);
                   }
 
diff --git a/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/GoGridComputeService.java b/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/GoGridComputeService.java
index b03aadf..aaa3b6e 100644
--- a/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/GoGridComputeService.java
+++ b/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/GoGridComputeService.java
@@ -31,6 +31,7 @@
 import org.jclouds.Constants;
 import org.jclouds.collect.Memoized;
 import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.compute.ImageExtension;
 import org.jclouds.compute.callables.RunScriptOnNode;
 import org.jclouds.compute.domain.Hardware;
 import org.jclouds.compute.domain.Image;
@@ -53,6 +54,7 @@
 import org.jclouds.gogrid.compute.options.GoGridTemplateOptions;
 import org.jclouds.scriptbuilder.functions.InitAdminAccess;
 
+import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;
 
@@ -74,12 +76,12 @@
          @Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
          InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess,
          RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
-         @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
+         @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, Optional<ImageExtension> imageExtension) {
       super(context, credentialStore, images, hardwareProfiles, locations, listNodesStrategy, getNodeMetadataStrategy,
             runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, resumeNodeStrategy,
             suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
             nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials, timeouts,
-            executor);
+            executor, imageExtension);
    }
 
    /**
diff --git a/providers/hpcloud-compute/src/test/java/org/jclouds/hpcloud/compute/compute/HPCloudComputeImageExtensionLivetest.java b/providers/hpcloud-compute/src/test/java/org/jclouds/hpcloud/compute/compute/HPCloudComputeImageExtensionLivetest.java
new file mode 100644
index 0000000..f632f51
--- /dev/null
+++ b/providers/hpcloud-compute/src/test/java/org/jclouds/hpcloud/compute/compute/HPCloudComputeImageExtensionLivetest.java
@@ -0,0 +1,44 @@
+/**
+ * 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.hpcloud.compute.compute;
+
+import org.jclouds.compute.internal.BaseImageExtensionLiveTest;
+import org.jclouds.sshj.config.SshjSshClientModule;
+import org.testng.annotations.Test;
+
+import com.google.inject.Module;
+
+/**
+ * 
+ * @author David Alves
+ * 
+ */
+@Test(groups = "live", singleThreaded = true, testName = "HPCloudComputeImageExtensionLivetest")
+public class HPCloudComputeImageExtensionLivetest extends BaseImageExtensionLiveTest {
+
+   public HPCloudComputeImageExtensionLivetest() {
+      provider = "hpcloud-compute";
+   }
+
+   @Override
+   protected Module getSshModule() {
+      return new SshjSshClientModule();
+   }
+}
diff --git a/sandbox-apis/libvirt/src/main/java/org/jclouds/libvirt/compute/LibvirtComputeService.java b/sandbox-apis/libvirt/src/main/java/org/jclouds/libvirt/compute/LibvirtComputeService.java
index 93a4c97..2f83bde 100644
--- a/sandbox-apis/libvirt/src/main/java/org/jclouds/libvirt/compute/LibvirtComputeService.java
+++ b/sandbox-apis/libvirt/src/main/java/org/jclouds/libvirt/compute/LibvirtComputeService.java
@@ -31,6 +31,7 @@
 import org.jclouds.Constants;
 import org.jclouds.collect.Memoized;
 import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.compute.ImageExtension;
 import org.jclouds.compute.callables.RunScriptOnNode;
 import org.jclouds.compute.domain.Hardware;
 import org.jclouds.compute.domain.Image;
@@ -55,6 +56,7 @@
 import org.libvirt.StorageVol;
 import org.xml.sax.InputSource;
 
+import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;
 import com.google.common.base.Throwables;
@@ -85,12 +87,13 @@
             @Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended,
             InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess,
             RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials,
-            Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, Connect client) {
+            Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, Connect client,
+            Optional<ImageExtension> imageExtension) {
       super(context, credentialStore, images, hardwareProfiles, locations, listNodesStrategy, getNodeMetadataStrategy,
                runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, resumeNodeStrategy,
                suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
                nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials,
-               timeouts, executor);
+               timeouts, executor, imageExtension);
       this.client = client;
    }