You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by na...@apache.org on 2018/01/08 14:52:25 UTC

[04/50] [abbrv] jclouds git commit: Initial support ManagedDataDisks

Initial support ManagedDataDisks

- add DiskApi + tests
- add ImageApi + tests
- add TemplateOptions.dataDisks
- use dataDisks in adapter
- fix CreateOptions enum usage
- fix VirtualMachineApiMockTest


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/37dcb87d
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/37dcb87d
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/37dcb87d

Branch: refs/heads/master
Commit: 37dcb87dfa261ab42f91f304eaf7ed8c6ecd7635
Parents: c45728e
Author: Andrea Turli <an...@gmail.com>
Authored: Thu Feb 23 14:52:41 2017 +0100
Committer: Andrea Turli <an...@gmail.com>
Committed: Tue Apr 11 11:45:18 2017 +0200

----------------------------------------------------------------------
 .../azurecompute/arm/AzureComputeApi.java       |  18 +-
 .../arm/AzureComputeProviderMetadata.java       |  11 +-
 .../arm/compute/AzureComputeServiceAdapter.java | 218 ++++++++++---------
 .../arm/compute/functions/VMImageToImage.java   |  15 +-
 .../compute/options/AzureTemplateOptions.java   | 100 ++++++---
 .../CreateResourceGroupThenCreateNodes.java     |  92 +-------
 .../azurecompute/arm/domain/CreationData.java   |  54 +++++
 .../azurecompute/arm/domain/DataDisk.java       |  98 +++++++--
 .../jclouds/azurecompute/arm/domain/Disk.java   | 105 +++++++++
 .../azurecompute/arm/domain/DiskProperties.java |  78 +++++++
 .../jclouds/azurecompute/arm/domain/Image.java  |  73 +++++++
 .../arm/domain/ImageProperties.java             |  70 ++++++
 .../azurecompute/arm/domain/ImageReference.java |  20 +-
 .../arm/domain/ManagedDiskParameters.java       |  65 ++++++
 .../jclouds/azurecompute/arm/domain/OSDisk.java |  18 +-
 .../azurecompute/arm/features/DiskApi.java      |  81 +++++++
 .../azurecompute/arm/features/ImageApi.java     |  81 +++++++
 .../azurecompute/arm/features/OSImageApi.java   |   5 +-
 .../jclouds/azurecompute/arm/util/VMImages.java |  27 +++
 .../arm/features/DiskApiLiveTest.java           | 107 +++++++++
 .../arm/features/DiskApiMockTest.java           | 141 ++++++++++++
 .../arm/features/ImageApiLiveTest.java          | 105 +++++++++
 .../arm/features/VirtualMachineApiLiveTest.java |  25 ++-
 .../arm/features/VirtualMachineApiMockTest.java |  50 ++---
 .../arm/internal/AzureLiveTestUtils.java        |   8 +-
 .../src/test/resources/creatediskresponse.json  |  11 +
 .../src/test/resources/getdisk.json             |  19 ++
 .../src/test/resources/image.json               |  43 ++++
 .../src/test/resources/listdisks.json           |  23 ++
 29 files changed, 1466 insertions(+), 295 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/37dcb87d/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeApi.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeApi.java
index 3700069..51ed402 100644
--- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeApi.java
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeApi.java
@@ -22,9 +22,11 @@ import javax.ws.rs.PathParam;
 
 import org.jclouds.azurecompute.arm.features.AvailabilitySetApi;
 import org.jclouds.azurecompute.arm.features.DeploymentApi;
+import org.jclouds.azurecompute.arm.features.ImageApi;
 import org.jclouds.azurecompute.arm.features.JobApi;
 import org.jclouds.azurecompute.arm.features.LoadBalancerApi;
 import org.jclouds.azurecompute.arm.features.LocationApi;
+import org.jclouds.azurecompute.arm.features.DiskApi;
 import org.jclouds.azurecompute.arm.features.NetworkInterfaceCardApi;
 import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi;
 import org.jclouds.azurecompute.arm.features.NetworkSecurityRuleApi;
@@ -37,7 +39,6 @@ import org.jclouds.azurecompute.arm.features.SubnetApi;
 import org.jclouds.azurecompute.arm.features.VMSizeApi;
 import org.jclouds.azurecompute.arm.features.VirtualMachineApi;
 import org.jclouds.azurecompute.arm.features.VirtualNetworkApi;
-
 import org.jclouds.rest.annotations.Delegate;
 
 /**
@@ -189,4 +190,19 @@ public interface AzureComputeApi extends Closeable {
    @Delegate
    ResourceProviderApi getResourceProviderApi();
 
+   /**
+    * The ManagedDataDisk API includes operations for managing data disks within your subscription.
+    *
+    * @see <a href="https://docs.microsoft.com/en-us/rest/api/manageddisks/disks/disks-rest-api">docs</a>
+    */
+   @Delegate
+   DiskApi getDiskApi(@PathParam("resourcegroup") String resourcegroup);
+
+   /**
+    * The virtual machine image API includes operations for managing data disks within your subscription.
+    *
+    * @see <a href="https://docs.microsoft.com/en-us/rest/api/manageddisks/images/images-rest-api">docs</a>
+    */
+   @Delegate
+   ImageApi getVirtualMachineImageApi(@PathParam("resourcegroup") String resourcegroup);
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/37dcb87d/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeProviderMetadata.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeProviderMetadata.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeProviderMetadata.java
index 08979b7..3bf1ab3 100644
--- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeProviderMetadata.java
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeProviderMetadata.java
@@ -23,8 +23,10 @@ import java.util.Properties;
 import org.jclouds.azurecompute.arm.domain.Region;
 import org.jclouds.azurecompute.arm.features.AvailabilitySetApi;
 import org.jclouds.azurecompute.arm.features.DeploymentApi;
+import org.jclouds.azurecompute.arm.features.ImageApi;
 import org.jclouds.azurecompute.arm.features.LoadBalancerApi;
 import org.jclouds.azurecompute.arm.features.LocationApi;
+import org.jclouds.azurecompute.arm.features.DiskApi;
 import org.jclouds.azurecompute.arm.features.NetworkInterfaceCardApi;
 import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi;
 import org.jclouds.azurecompute.arm.features.NetworkSecurityRuleApi;
@@ -109,14 +111,11 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata {
       properties.put(API_VERSION_PREFIX + SubnetApi.class.getSimpleName(), "2015-06-15");
       properties.put(API_VERSION_PREFIX + VirtualNetworkApi.class.getSimpleName(), "2015-06-15");
       properties.put(API_VERSION_PREFIX + VMSizeApi.class.getSimpleName(), "2015-06-15");
-      properties.put(API_VERSION_PREFIX + VirtualMachineApi.class.getSimpleName(), "2015-06-15");
+      properties.put(API_VERSION_PREFIX + VirtualMachineApi.class.getSimpleName(), "2016-04-30-preview");
       properties.put(API_VERSION_PREFIX + LoadBalancerApi.class.getSimpleName(), "2016-03-30");
       properties.put(API_VERSION_PREFIX + AvailabilitySetApi.class.getSimpleName(), "2016-03-30");
-      properties.put(API_VERSION_PREFIX + "GetVirtualMachine", "2016-03-30");
-      properties.put(API_VERSION_PREFIX + "GetVirtualMachineInstance", "2016-03-30");
-      properties.put(API_VERSION_PREFIX + "CreateOrUpdateVirtualMachine", "2016-03-30");
-      properties.put(API_VERSION_PREFIX + "ListVirtualMachines", "2015-06-15");
-      properties.put(API_VERSION_PREFIX + "DeleteVirtualMachine", "2016-03-30");
+      properties.put(API_VERSION_PREFIX + DiskApi.class.getSimpleName(), "2017-03-30");
+      properties.put(API_VERSION_PREFIX + ImageApi.class.getSimpleName(), "2016-04-30-preview");
       
       return properties;
    }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/37dcb87d/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java
index 572e2be..e79c50d 100644
--- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java
@@ -16,23 +16,10 @@
  */
 package org.jclouds.azurecompute.arm.compute;
 
-import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.collect.Iterables.contains;
-import static com.google.common.collect.Iterables.filter;
-import static com.google.common.collect.Iterables.find;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageExtension.CONTAINER_NAME;
-import static org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageExtension.CUSTOM_IMAGE_OFFER;
-import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.decodeFieldsFromUniqueId;
-import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.encodeFieldsToUniqueIdCustom;
-import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.getMarketplacePlanFromImageMetadata;
-import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS;
-import static org.jclouds.compute.util.ComputeServiceUtils.metadataAndTagsAsCommaDelimitedValue;
-import static org.jclouds.util.Closeables2.closeQuietly;
-
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+
 import javax.annotation.Resource;
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -42,6 +29,8 @@ import org.jclouds.azurecompute.arm.AzureComputeApi;
 import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.PublicIpAvailablePredicateFactory;
 import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions;
 import org.jclouds.azurecompute.arm.compute.strategy.CleanupResources;
+import org.jclouds.azurecompute.arm.domain.AvailabilitySet;
+import org.jclouds.azurecompute.arm.domain.CreationData;
 import org.jclouds.azurecompute.arm.domain.DataDisk;
 import org.jclouds.azurecompute.arm.domain.HardwareProfile;
 import org.jclouds.azurecompute.arm.domain.IdReference;
@@ -49,6 +38,7 @@ import org.jclouds.azurecompute.arm.domain.ImageReference;
 import org.jclouds.azurecompute.arm.domain.IpConfiguration;
 import org.jclouds.azurecompute.arm.domain.IpConfigurationProperties;
 import org.jclouds.azurecompute.arm.domain.Location;
+import org.jclouds.azurecompute.arm.domain.ManagedDiskParameters;
 import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard;
 import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCardProperties;
 import org.jclouds.azurecompute.arm.domain.NetworkProfile;
@@ -66,7 +56,6 @@ import org.jclouds.azurecompute.arm.domain.StorageProfile;
 import org.jclouds.azurecompute.arm.domain.StorageService;
 import org.jclouds.azurecompute.arm.domain.StorageService.Status;
 import org.jclouds.azurecompute.arm.domain.StorageServiceKeys;
-import org.jclouds.azurecompute.arm.domain.VHD;
 import org.jclouds.azurecompute.arm.domain.VMHardware;
 import org.jclouds.azurecompute.arm.domain.VMImage;
 import org.jclouds.azurecompute.arm.domain.VMSize;
@@ -97,6 +86,23 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.ImmutableList.builder;
+import static com.google.common.collect.ImmutableList.of;
+import static com.google.common.collect.Iterables.contains;
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.find;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageExtension.CONTAINER_NAME;
+import static org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageExtension.CUSTOM_IMAGE_OFFER;
+import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.decodeFieldsFromUniqueId;
+import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.encodeFieldsToUniqueIdCustom;
+import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.getMarketplacePlanFromImageMetadata;
+import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS;
+import static org.jclouds.azurecompute.arm.util.VMImages.isCustom;
+import static org.jclouds.compute.util.ComputeServiceUtils.metadataAndTagsAsCommaDelimitedValue;
+import static org.jclouds.util.Closeables2.closeQuietly;
+
 /**
  * Defines the connection between the {@link AzureComputeApi} implementation and
  * the jclouds {@link org.jclouds.compute.ComputeService}.
@@ -105,11 +111,11 @@ import com.google.common.collect.Lists;
 public class AzureComputeServiceAdapter implements ComputeServiceAdapter<VirtualMachine, VMHardware, VMImage, Location> {
 
    public static final String GROUP_KEY = "jclouds_group";
-   
+
    @Resource
    @Named(ComputeServiceConstants.COMPUTE_LOGGER)
    protected Logger logger = Logger.NULL;
-   
+
    private final CleanupResources cleanupResources;
    private final AzureComputeApi api;
    private final List<String> imagePublishers;
@@ -119,8 +125,8 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual
 
    @Inject
    AzureComputeServiceAdapter(final AzureComputeApi api, @Named(IMAGE_PUBLISHERS) String imagePublishers,
-         CleanupResources cleanupResources, @Region Supplier<Set<String>> regionIds,
-         PublicIpAvailablePredicateFactory publicIpAvailable, LoadingCache<String, ResourceGroup> resourceGroupMap) {
+                              CleanupResources cleanupResources, @Region Supplier<Set<String>> regionIds,
+                              PublicIpAvailablePredicateFactory publicIpAvailable, LoadingCache<String, ResourceGroup> resourceGroupMap) {
       this.api = api;
       this.imagePublishers = Splitter.on(',').trimResults().omitEmptyStrings().splitToList(imagePublishers);
       this.cleanupResources = cleanupResources;
@@ -130,35 +136,32 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual
    }
 
    @Override
-   public NodeAndInitialCredentials<VirtualMachine> createNodeWithGroupEncodedIntoName(final String group,
-         final String name, final Template template) {
-
-      AzureTemplateOptions templateOptions = template.getOptions().as(AzureTemplateOptions.class);
-      ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(template.getLocation().getId());
-
-      // TODO ARM specific options
-      // TODO network ids => createOrUpdate one nic in each network
-      
-      IdReference availabilitySet = null;
-      if (templateOptions.getAvailabilitySet() != null) {
-         availabilitySet = IdReference.create(templateOptions.getAvailabilitySet().id());
-      }
+   public NodeAndInitialCredentials<VirtualMachine> createNodeWithGroupEncodedIntoName(final String group, final String name, final Template template) {
+      // TODO network ids => create one nic in each network
 
       String locationName = template.getLocation().getId();
+      Image image = template.getImage();
+      String hardwareId = template.getHardware().getId();
+      ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(locationName);
+      // TODO ARM specific options
+      AzureTemplateOptions templateOptions = template.getOptions().as(AzureTemplateOptions.class);
       String subnetId = templateOptions.getSubnetId();
-      NetworkInterfaceCard nic = createNetworkInterfaceCard(subnetId, name, locationName, resourceGroup.name(),
-            template.getOptions());
-      StorageProfile storageProfile = createStorageProfile(name, template.getImage(), templateOptions.getBlob());
-      HardwareProfile hardwareProfile = HardwareProfile.builder().vmSize(template.getHardware().getId()).build();
+      
+      IdReference availabilitySet = getAvailabilitySetIdReference(templateOptions.getAvailabilitySet());
+      StorageProfile storageProfile = createStorageProfile(image, templateOptions.getDataDisks());
+      NetworkInterfaceCard nic = createNetworkInterfaceCard(subnetId, name, locationName, resourceGroup.name(), template.getOptions());
+      HardwareProfile hardwareProfile = HardwareProfile.builder().vmSize(hardwareId).build();
       OSProfile osProfile = createOsProfile(name, template);
-      NetworkProfile networkProfile = NetworkProfile.builder()
-            .networkInterfaces(ImmutableList.of(IdReference.create(nic.id()))).build();
+      NetworkProfile networkProfile = NetworkProfile.builder().networkInterfaces(of(IdReference.create(nic.id()))).build();
       VirtualMachineProperties virtualMachineProperties = VirtualMachineProperties.builder()
-            .licenseType(null) // TODO
-            .availabilitySet(availabilitySet)
-            .hardwareProfile(hardwareProfile).storageProfile(storageProfile).osProfile(osProfile)
-            .networkProfile(networkProfile).build();
-      
+              .licenseType(null) // TODO
+              .availabilitySet(availabilitySet)
+              .hardwareProfile(hardwareProfile)
+              .storageProfile(storageProfile)
+              .osProfile(osProfile)
+              .networkProfile(networkProfile)
+              .build();
+
       // Store group apart from the name to be able to identify nodes with
       // custom names in the configured group
       template.getOptions().getUserMetadata().put(GROUP_KEY, group);
@@ -171,7 +174,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual
       // Safe to pass null credentials here, as jclouds will default populate
       // the node with the default credentials from the image, or the ones in
       // the options, if provided.
-      RegionAndId regionAndId = RegionAndId.fromRegionAndId(template.getLocation().getId(), name);
+      RegionAndId regionAndId = RegionAndId.fromRegionAndId(locationName, name);
       return new NodeAndInitialCredentials<VirtualMachine>(virtualMachine, regionAndId.slashEncode(), null);
    }
 
@@ -182,9 +185,9 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual
          Iterable<VMSize> vmSizes = api.getVMSizeApi(location.name()).list();
          for (VMSize vmSize : vmSizes) {
             VMHardware hwProfile = VMHardware
-                  .create(vmSize.name(), vmSize.numberOfCores(), vmSize.osDiskSizeInMB(),
-                        vmSize.resourceDiskSizeInMB(), vmSize.memoryInMB(), vmSize.maxDataDiskCount(), location.name(),
-                        false);
+                    .create(vmSize.name(), vmSize.numberOfCores(), vmSize.osDiskSizeInMB(),
+                            vmSize.resourceDiskSizeInMB(), vmSize.memoryInMB(), vmSize.maxDataDiskCount(), location.name(),
+                            false);
             hwProfiles.add(hwProfile);
          }
       }
@@ -204,8 +207,8 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual
             for (Version version : versionList) {
                Version versionDetails = osImageApi.getVersion(publisherName, offer.name(), sku.name(), version.name());
                VMImage vmImage = VMImage.azureImage().publisher(publisherName).offer(offer.name()).sku(sku.name())
-                     .version(versionDetails.name()).location(location).versionProperties(versionDetails.properties())
-                     .build();
+                       .version(versionDetails.name()).location(location).versionProperties(versionDetails.properties())
+                       .build();
                osImagesRef.add(vmImage);
             }
          }
@@ -245,13 +248,13 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual
             try {
                String name = storage.name();
                StorageService storageService = api.getStorageAccountApi(azureGroup).get(name);
-               if (storageService != null && availableLocationNames.contains(storageService.location())
-                     && Status.Succeeded == storageService.storageServiceProperties().provisioningState()) {
+               if (storageService != null
+                       && Status.Succeeded == storageService.storageServiceProperties().provisioningState()) {
                   String key = api.getStorageAccountApi(azureGroup).getKeys(name).key1();
                   BlobHelper blobHelper = new BlobHelper(storage.name(), key);
                   try {
                      List<VMImage> images = blobHelper.getImages(CONTAINER_NAME, azureGroup, CUSTOM_IMAGE_OFFER,
-                           storage.location());
+                             storage.location());
                      osImages.addAll(images);
                   } finally {
                      closeQuietly(blobHelper);
@@ -284,7 +287,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual
          try {
             if (blobHelper.customImageExists()) {
                List<VMImage> customImagesInStorage = blobHelper.getImages(CONTAINER_NAME, resourceGroup.name(),
-                     CUSTOM_IMAGE_OFFER, image.location());
+                       CUSTOM_IMAGE_OFFER, image.location());
                customImage = find(customImagesInStorage, new Predicate<VMImage>() {
                   @Override
                   public boolean apply(VMImage input) {
@@ -308,7 +311,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual
       if (!versions.isEmpty()) {
          Version version = osImageApi.getVersion(publisher, offer, sku, versions.get(0).name());
          return VMImage.azureImage().publisher(publisher).offer(offer).sku(sku).version(version.name())
-               .location(location).versionProperties(version.properties()).build();
+                 .location(location).versionProperties(version.properties()).build();
       }
       return null;
    }
@@ -316,17 +319,17 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual
    @Override
    public Iterable<Location> listLocations() {
       final Iterable<String> vmLocations = FluentIterable.from(api.getResourceProviderApi().get("Microsoft.Compute"))
-            .filter(new Predicate<ResourceProviderMetaData>() {
-               @Override
-               public boolean apply(ResourceProviderMetaData input) {
-                  return input.resourceType().equals("virtualMachines");
-               }
-            }).transformAndConcat(new Function<ResourceProviderMetaData, Iterable<String>>() {
-               @Override
-               public Iterable<String> apply(ResourceProviderMetaData resourceProviderMetaData) {
-                  return resourceProviderMetaData.locations();
-               }
-            });
+              .filter(new Predicate<ResourceProviderMetaData>() {
+                 @Override
+                 public boolean apply(ResourceProviderMetaData input) {
+                    return input.resourceType().equals("virtualMachines");
+                 }
+              }).transformAndConcat(new Function<ResourceProviderMetaData, Iterable<String>>() {
+                 @Override
+                 public Iterable<String> apply(ResourceProviderMetaData resourceProviderMetaData) {
+                    return resourceProviderMetaData.locations();
+                 }
+              });
 
       List<Location> locations = FluentIterable.from(api.getLocationApi().list()).filter(new Predicate<Location>() {
          @Override
@@ -378,7 +381,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual
 
    @Override
    public Iterable<VirtualMachine> listNodes() {
-      ImmutableList.Builder<VirtualMachine> nodes = ImmutableList.builder();
+      ImmutableList.Builder<VirtualMachine> nodes = builder();
       for (ResourceGroup resourceGroup : api.getResourceGroupApi().list()) {
          nodes.addAll(api.getVirtualMachineApi(resourceGroup.name()).list());
       }
@@ -401,14 +404,14 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual
       String adminUsername = Objects.firstNonNull(template.getOptions().getLoginUser(), defaultLoginUser);
       String adminPassword = Objects.firstNonNull(template.getOptions().getLoginPassword(), defaultLoginPassword);
       OSProfile.Builder builder = OSProfile.builder().adminUsername(adminUsername).adminPassword(adminPassword)
-            .computerName(computerName);
+              .computerName(computerName);
 
       if (template.getOptions().getPublicKey() != null
-            && OsFamily.WINDOWS != template.getImage().getOperatingSystem().getFamily()) {
+              && OsFamily.WINDOWS != template.getImage().getOperatingSystem().getFamily()) {
          OSProfile.LinuxConfiguration linuxConfiguration = OSProfile.LinuxConfiguration.create("true",
-               OSProfile.LinuxConfiguration.SSH.create(ImmutableList.of(OSProfile.LinuxConfiguration.SSH.SSHPublicKey
-                     .create(String.format("/home/%s/.ssh/authorized_keys", adminUsername), template.getOptions()
-                           .getPublicKey()))));
+                 OSProfile.LinuxConfiguration.SSH.create(of(OSProfile.LinuxConfiguration.SSH.SSHPublicKey
+                         .create(String.format("/home/%s/.ssh/authorized_keys", adminUsername), template.getOptions()
+                                 .getPublicKey()))));
          builder.linuxConfiguration(linuxConfiguration);
       }
 
@@ -416,29 +419,29 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual
    }
 
    private NetworkInterfaceCard createNetworkInterfaceCard(String subnetId, String name, String locationName,
-         String azureGroup, TemplateOptions options) {
+                                                           String azureGroup, TemplateOptions options) {
       final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(azureGroup);
 
       PublicIPAddressProperties properties = PublicIPAddressProperties.builder().publicIPAllocationMethod("Static")
-            .idleTimeoutInMinutes(4).build();
+              .idleTimeoutInMinutes(4).build();
 
       String publicIpAddressName = "public-address-" + name;
       PublicIPAddress ip = ipApi.createOrUpdate(publicIpAddressName, locationName, ImmutableMap.of("jclouds", name),
-            properties);
+              properties);
 
       checkState(publicIpAvailable.create(azureGroup).apply(publicIpAddressName),
-            "Public IP was not provisioned in the configured timeout");
+              "Public IP was not provisioned in the configured timeout");
 
       final NetworkInterfaceCardProperties.Builder networkInterfaceCardProperties = NetworkInterfaceCardProperties
-            .builder()
-            .ipConfigurations(
-                  ImmutableList.of(IpConfiguration
-                        .builder()
-                        .name("ipConfig-" + name)
-                        .properties(
-                              IpConfigurationProperties.builder().privateIPAllocationMethod("Dynamic")
-                                    .publicIPAddress(IdReference.create(ip.id())).subnet(IdReference.create(subnetId))
-                                    .build()).build()));
+              .builder()
+              .ipConfigurations(
+                      of(IpConfiguration
+                              .builder()
+                              .name("ipConfig-" + name)
+                              .properties(
+                                      IpConfigurationProperties.builder().privateIPAllocationMethod("Dynamic")
+                                              .publicIPAddress(IdReference.create(ip.id())).subnet(IdReference.create(subnetId))
+                                              .build()).build()));
 
       String securityGroup = getOnlyElement(options.getGroups(), null);
       if (securityGroup != null) {
@@ -447,29 +450,36 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual
 
       String networkInterfaceCardName = "jc-nic-" + name;
       return api.getNetworkInterfaceCardApi(azureGroup).createOrUpdate(networkInterfaceCardName, locationName,
-            networkInterfaceCardProperties.build(), ImmutableMap.of("jclouds", name));
+              networkInterfaceCardProperties.build(), ImmutableMap.of("jclouds", name));
    }
 
-   private StorageProfile createStorageProfile(String name, Image image, String blob) {
-      VMImage imageRef = decodeFieldsFromUniqueId(image.getId());
-      ImageReference imageReference = null;
-      VHD sourceImage = null;
-      String osType = null;
-
-      if (!imageRef.custom()) {
-         imageReference = ImageReference.builder().publisher(image.getProviderId()).offer(image.getName())
-               .sku(image.getVersion()).version("latest").build();
-      } else {
-         sourceImage = VHD.create(image.getProviderId());
-
-         // TODO: read the ostype from the image blob
-         OsFamily osFamily = image.getOperatingSystem().getFamily();
-         osType = osFamily == OsFamily.WINDOWS ? "Windows" : "Linux";
-      }
+   private StorageProfile createStorageProfile(Image image, List<DataDisk> dataDisks) {
+      return StorageProfile.create(createImageReference(image), createOSDisk(image), dataDisks);
+   }
 
-      VHD vhd = VHD.create(blob + "vhds/" + name + ".vhd");
-      OSDisk osDisk = OSDisk.create(osType, name, vhd, "ReadWrite", "FromImage", sourceImage);
+   private ImageReference createImageReference(Image image) {
+      return isCustom(image.getId()) ? ImageReference.builder().id(image.getId()).build() :
+              ImageReference.builder()
+                      .publisher(image.getProviderId())
+                      .offer(image.getName())
+                      .sku(image.getVersion())
+                      .version("latest")
+                      .build();
+   }
 
-      return StorageProfile.create(imageReference, osDisk, ImmutableList.<DataDisk> of());
+   private OSDisk createOSDisk(Image image) {
+      OsFamily osFamily = image.getOperatingSystem().getFamily();
+      String osType = osFamily == OsFamily.WINDOWS ? "Windows" : "Linux";
+      return OSDisk.builder()
+              .osType(osType)
+              .caching(DataDisk.CachingTypes.READ_WRITE.toString())
+              .createOption(CreationData.CreateOptions.FROM_IMAGE.toString())
+              .managedDiskParameters(ManagedDiskParameters.create(null, ManagedDiskParameters.StorageAccountTypes.STANDARD_LRS.toString()))
+              .build();
    }
+   
+   private IdReference getAvailabilitySetIdReference(AvailabilitySet availabilitySet) {
+      return availabilitySet != null ? IdReference.create(availabilitySet.id()) : null;
+   }
+
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/37dcb87d/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java
index 38c0769..25bcc3b 100644
--- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java
@@ -16,10 +16,6 @@
  */
 package org.jclouds.azurecompute.arm.compute.functions;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Iterables.tryFind;
-import static java.util.Arrays.asList;
-
 import java.util.Map;
 import java.util.Set;
 
@@ -43,6 +39,11 @@ import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableMap;
 import com.google.inject.Inject;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.tryFind;
+import static java.util.Arrays.asList;
+import static org.jclouds.azurecompute.arm.util.VMImages.isCustom;
+
 public class VMImageToImage implements Function<VMImage, Image> {
 
    private static final Map<String, OsFamily> OTHER_OS_MAP = ImmutableMap.<String, OsFamily> builder()
@@ -71,10 +72,9 @@ public class VMImageToImage implements Function<VMImage, Image> {
    }
 
    public static VMImage decodeFieldsFromUniqueId(final String id) {
-      String[] fields = checkNotNull(id, "id").split("/");
       VMImage vmImage;
-      boolean custom = fields.length == 5;
-      if (custom) {
+      String[] fields = checkNotNull(id, "id").split("/");
+      if (isCustom(id)) {
          /* id fields indexes
          0: imageReference.location) + "/" +
          1: imageReference.group + "/" +
@@ -193,4 +193,5 @@ public class VMImageToImage implements Function<VMImage, Image> {
          }
       });
    }
+
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/37dcb87d/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/AzureTemplateOptions.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/AzureTemplateOptions.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/AzureTemplateOptions.java
index ec6858f..5566ecf 100644
--- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/AzureTemplateOptions.java
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/AzureTemplateOptions.java
@@ -16,12 +16,16 @@
  */
 package org.jclouds.azurecompute.arm.compute.options;
 
+import java.util.List;
+
 import org.jclouds.azurecompute.arm.domain.AvailabilitySet;
+import org.jclouds.azurecompute.arm.domain.DataDisk;
 import org.jclouds.compute.options.TemplateOptions;
 
 import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
 
-import static com.google.common.base.Objects.equal;
+import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
  * Azure ARM custom options
@@ -33,6 +37,7 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable {
    private String blob;
    private AvailabilitySet availabilitySet;
    private String availabilitySetName;
+   private List<DataDisk> dataDisks = ImmutableList.of();
 
    /**
     * Sets the virtual network name
@@ -76,12 +81,25 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable {
       return this;
    }
 
+   public AzureTemplateOptions dataDisks(Iterable<DataDisk> dataDisks) {
+      for (DataDisk dataDisk : checkNotNull(dataDisks, "dataDisks"))
+         checkNotNull(dataDisk, "all dataDisks must be non-empty");
+      this.dataDisks = ImmutableList.copyOf(dataDisks);
+      return this;
+   }
+
+   public AzureTemplateOptions dataDisks(DataDisk... dataDisks) {
+      return dataDisks(ImmutableList.copyOf(checkNotNull(dataDisks, "dataDisks")));
+   }
+   
    public String getVirtualNetworkName() { return virtualNetworkName; }
    public String getSubnetId() { return subnetId; }
    public String getBlob() { return blob; }
    public AvailabilitySet getAvailabilitySet() { return availabilitySet; }
    public String getAvailabilitySetName() { return availabilitySetName; }
-
+   public List<DataDisk> getDataDisks() {
+      return dataDisks;
+   }
 
    @Override
    public AzureTemplateOptions clone() {
@@ -100,43 +118,56 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable {
          eTo.blob(blob);
          eTo.availabilitySet(availabilitySet);
          eTo.availabilitySet(availabilitySetName);
+         eTo.dataDisks(dataDisks);
       }
    }
 
    @Override
-   public int hashCode() {
-      return Objects.hashCode(super.hashCode(), virtualNetworkName, subnetId, blob, availabilitySet,
-            availabilitySetName);
-   }
+   public boolean equals(Object o) {
+      if (this == o) return true;
+      if (!(o instanceof AzureTemplateOptions)) return false;
+      if (!super.equals(o)) return false;
 
-   @Override
-   public boolean equals(Object obj) {
-      if (this == obj) {
-         return true;
-      }
-      if (!super.equals(obj)) {
+      AzureTemplateOptions that = (AzureTemplateOptions) o;
+
+      if (virtualNetworkName != null ? !virtualNetworkName.equals(that.virtualNetworkName) : that.virtualNetworkName != null)
          return false;
-      }
-      if (getClass() != obj.getClass()) {
+      if (subnetId != null ? !subnetId.equals(that.subnetId) : that.subnetId != null) return false;
+      if (blob != null ? !blob.equals(that.blob) : that.blob != null) return false;
+      if (availabilitySet != null ? !availabilitySet.equals(that.availabilitySet) : that.availabilitySet != null)
          return false;
-      }
-      AzureTemplateOptions other = (AzureTemplateOptions) obj;
-      return super.equals(other)
-            && equal(this.virtualNetworkName, other.virtualNetworkName)
-            && equal(this.subnetId, other.subnetId)
-            && equal(this.blob, other.blob)
-            && equal(this.availabilitySet, other.availabilitySet)
-            && equal(this.availabilitySetName, other.availabilitySetName);
+      if (availabilitySetName != null ? !availabilitySetName.equals(that.availabilitySetName) : that.availabilitySetName != null)
+         return false;
+      return dataDisks != null ? dataDisks.equals(that.dataDisks) : that.dataDisks == null;
+   }
+
+   @Override
+   public int hashCode() {
+      int result = super.hashCode();
+      result = 31 * result + (virtualNetworkName != null ? virtualNetworkName.hashCode() : 0);
+      result = 31 * result + (subnetId != null ? subnetId.hashCode() : 0);
+      result = 31 * result + (blob != null ? blob.hashCode() : 0);
+      result = 31 * result + (availabilitySet != null ? availabilitySet.hashCode() : 0);
+      result = 31 * result + (availabilitySetName != null ? availabilitySetName.hashCode() : 0);
+      result = 31 * result + (dataDisks != null ? dataDisks.hashCode() : 0);
+      return result;
    }
 
    @Override
    public Objects.ToStringHelper string() {
-      Objects.ToStringHelper toString = super.string().omitNullValues();
-      toString.add("virtualNetworkName", virtualNetworkName);
-      toString.add("subnetId", subnetId);
-      toString.add("blob", blob);
-      toString.add("availabilitySet", availabilitySet);
-      toString.add("availabilitySetName", availabilitySetName);
+      Objects.ToStringHelper toString = super.string();
+      if (virtualNetworkName != null)
+         toString.add("virtualNetworkName", virtualNetworkName);
+      if (subnetId != null)
+         toString.add("subnetId", subnetId);
+      if (blob != null)
+         toString.add("blob", blob);
+      if (availabilitySet != null)
+         toString.add("availabilitySet", availabilitySet);
+      if (availabilitySetName != null)
+         toString.add("availabilitySetName", availabilitySetName);
+      if (!dataDisks.isEmpty())
+         toString.add("dataDisks", dataDisks);
       return toString;
    }
 
@@ -181,5 +212,18 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable {
          AzureTemplateOptions options = new AzureTemplateOptions();
          return options.availabilitySet(availabilitySetName);
       }
+
+      /**
+       * @see AzureTemplateOptions#dataDisks
+       */
+      public static AzureTemplateOptions dataDisks(DataDisk... dataDisks) {
+         AzureTemplateOptions options = new AzureTemplateOptions();
+         return options.dataDisks(dataDisks);
+      }
+
+      public static AzureTemplateOptions dataDisks(Iterable<DataDisk> dataDisks) {
+         AzureTemplateOptions options = new AzureTemplateOptions();
+         return options.dataDisks(dataDisks);
+      }
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/37dcb87d/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourceGroupThenCreateNodes.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourceGroupThenCreateNodes.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourceGroupThenCreateNodes.java
index 92c9499..5f6d88f 100644
--- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourceGroupThenCreateNodes.java
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourceGroupThenCreateNodes.java
@@ -16,19 +16,9 @@
  */
 package org.jclouds.azurecompute.arm.compute.strategy;
 
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.decodeFieldsFromUniqueId;
-import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_SUBNET_ADDRESS_PREFIX;
-import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_VNET_ADDRESS_SPACE_PREFIX;
-
-import java.net.URI;
 import java.util.Arrays;
 import java.util.Map;
 import java.util.Set;
-import java.util.UUID;
 
 import javax.annotation.Resource;
 import javax.inject.Inject;
@@ -44,14 +34,11 @@ import org.jclouds.azurecompute.arm.domain.AvailabilitySet;
 import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup;
 import org.jclouds.azurecompute.arm.domain.RegionAndId;
 import org.jclouds.azurecompute.arm.domain.ResourceGroup;
-import org.jclouds.azurecompute.arm.domain.StorageService;
 import org.jclouds.azurecompute.arm.domain.Subnet;
-import org.jclouds.azurecompute.arm.domain.VMImage;
 import org.jclouds.azurecompute.arm.domain.VirtualNetwork;
 import org.jclouds.azurecompute.arm.features.SubnetApi;
 import org.jclouds.azurecompute.arm.features.VirtualNetworkApi;
 import org.jclouds.compute.config.CustomizationResponse;
-import org.jclouds.compute.domain.Image;
 import org.jclouds.compute.domain.NodeMetadata;
 import org.jclouds.compute.domain.Template;
 import org.jclouds.compute.functions.GroupNamingConvention;
@@ -65,14 +52,17 @@ import org.jclouds.domain.Location;
 import org.jclouds.logging.Logger;
 
 import com.google.common.base.Optional;
-import com.google.common.base.Predicate;
-import com.google.common.base.Strings;
 import com.google.common.cache.LoadingCache;
-import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Multimap;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
 
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_SUBNET_ADDRESS_PREFIX;
+import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_VNET_ADDRESS_SPACE_PREFIX;
+
 @Singleton
 public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEncodedIntoNameThenAddToSet {
 
@@ -85,7 +75,6 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco
    private final LoadingCache<String, ResourceGroup> resourceGroupMap;
    private final String defaultVnetAddressPrefix;
    private final String defaultSubnetAddressPrefix;
-   private final Predicate<URI> storageAccountCreated;
    private final TemplateToAvailabilitySet templateToAvailabilitySet;
 
    @Inject
@@ -98,7 +87,7 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco
          AzureComputeApi api, @Named(DEFAULT_VNET_ADDRESS_SPACE_PREFIX) String defaultVnetAddressPrefix,
          @Named(DEFAULT_SUBNET_ADDRESS_PREFIX) String defaultSubnetAddressPrefix,
          LoadingCache<RegionAndIdAndIngressRules, String> securityGroupMap,
-         LoadingCache<String, ResourceGroup> resourceGroupMap, @Named("STORAGE") Predicate<URI> storageAccountCreated,
+         LoadingCache<String, ResourceGroup> resourceGroupMap, 
          TemplateToAvailabilitySet templateToAvailabilitySet) {
       super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor,
             customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory);
@@ -108,7 +97,6 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco
       this.resourceGroupMap = resourceGroupMap;
       this.defaultVnetAddressPrefix = defaultVnetAddressPrefix;
       this.defaultSubnetAddressPrefix = defaultSubnetAddressPrefix;
-      this.storageAccountCreated = storageAccountCreated;
       this.templateToAvailabilitySet = templateToAvailabilitySet;
    }
 
@@ -136,9 +124,6 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco
       configureSecurityGroupForOptions(group, azureGroupName, template.getLocation(), options);
       configureAvailabilitySetForTemplate(template);
 
-      StorageService storageService = getOrCreateStorageService(group, azureGroupName, location, template.getImage());
-      options.blob(storageService.storageServiceProperties().primaryEndpoints().get("blob"));
-
       return super.execute(group, count, template, goodNodes, badNodes, customizationResponses);
    }
 
@@ -175,32 +160,6 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco
             && !template.getOptions().hasLoginPrivateKeyOption();
    }
 
-   public StorageService getOrCreateStorageService(String name, String resourceGroupName, String locationName,
-         Image image) {
-      String storageAccountName = null;
-      VMImage imageRef = decodeFieldsFromUniqueId(image.getId());
-      if (imageRef.custom()) {
-         storageAccountName = imageRef.storage();
-      }
-
-      if (Strings.isNullOrEmpty(storageAccountName)) {
-         storageAccountName = generateStorageAccountName(name);
-      }
-
-      StorageService storageService = api.getStorageAccountApi(resourceGroupName).get(storageAccountName);
-      if (storageService != null)
-         return storageService;
-
-      URI uri = api.getStorageAccountApi(resourceGroupName).create(storageAccountName, locationName,
-            ImmutableMap.of("jclouds", name),
-            ImmutableMap.of("accountType", StorageService.AccountType.Standard_LRS.toString()));
-
-      checkState(storageAccountCreated.apply(uri), "Storage account %s was not created in the configured timeout",
-            storageAccountName);
-
-      return api.getStorageAccountApi(resourceGroupName).get(storageAccountName);
-   }
-
    private void configureSecurityGroupForOptions(String group, String resourceGroup, Location location,
          TemplateOptions options) {
 
@@ -231,41 +190,4 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco
          template.getOptions().as(AzureTemplateOptions.class).availabilitySet(availabilitySet);
       }
    }
-
-   /**
-    * Generates a valid storage account
-    *
-    * Storage account names must be between 3 and 24 characters in length and
-    * may contain numbers and lowercase letters only.
-    *
-    * @param name
-    *           the node name
-    * @return the storage account name starting from a sanitized name (with only
-    *         numbers and lowercase letters only ). If sanitized name is between
-    *         3 and 24 characters, storage account name is equals to sanitized
-    *         name. If sanitized name is less than 3 characters, storage account
-    *         is sanitized name plus 4 random chars. If sanitized name is more
-    *         than 24 characters, storage account is first 10 chars of sanitized
-    *         name plus 4 random chars plus last 10 chars of sanitized name.
-    */
-   public static String generateStorageAccountName(String name) {
-      String random = UUID.randomUUID().toString().substring(0, 4);
-      String storageAccountName = new StringBuilder().append(name).append(random).toString();
-      String sanitizedStorageAccountName = storageAccountName.replaceAll("[^a-z0-9]", "");
-      int nameLength = sanitizedStorageAccountName.length();
-      if (nameLength >= 3 && nameLength <= 24) {
-         return sanitizedStorageAccountName;
-      }
-
-      if (nameLength > 24) {
-         sanitizedStorageAccountName = shorten(sanitizedStorageAccountName, random);
-      }
-      return sanitizedStorageAccountName;
-   }
-
-   private static String shorten(String storageAccountName, String random) {
-      String prefix = storageAccountName.substring(0, 10);
-      String suffix = storageAccountName.substring(storageAccountName.length() - 10, storageAccountName.length());
-      return String.format("%s%s%s", prefix, random, suffix);
-   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/37dcb87d/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/CreationData.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/CreationData.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/CreationData.java
new file mode 100644
index 0000000..ff31ef2
--- /dev/null
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/CreationData.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.azurecompute.arm.domain;
+
+import org.jclouds.azurecompute.arm.util.GetEnumValue;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.base.CaseFormat;
+
+@AutoValue
+public abstract class CreationData {
+
+
+   public enum CreateOptions {
+      EMPTY,
+      FROM_IMAGE,
+      COPY,
+      IMPORT,
+      UNRECOGNIZED;
+
+      public static CreateOptions fromValue(final String text) {
+         return (CreateOptions) GetEnumValue.fromValueOrDefault(text, UNRECOGNIZED);
+      }
+
+      @Override
+      public String toString() {
+         return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name());
+      }
+   }
+   
+   @Nullable
+   public abstract CreateOptions createOption();
+
+   @SerializedNames({ "createOption" })
+   public static CreationData create(CreateOptions createOption) {
+      return new AutoValue_CreationData(createOption);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/37dcb87d/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DataDisk.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DataDisk.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DataDisk.java
index ebb137b..40189c3 100644
--- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DataDisk.java
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DataDisk.java
@@ -16,47 +16,108 @@
  */
 package org.jclouds.azurecompute.arm.domain;
 
-import com.google.auto.value.AutoValue;
-
+import org.jclouds.azurecompute.arm.util.GetEnumValue;
+import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.json.SerializedNames;
 
+import com.google.auto.value.AutoValue;
+import com.google.common.base.CaseFormat;
+
 @AutoValue
-public abstract class DataDisk {
+public abstract class DataDisk implements Provisionable {
+
+   public enum DiskCreateOptionTypes {
+      FROM_IMAGE,
+      EMPTY,
+      ATTACH,
+      UNRECOGNIZED;
+
+      public static DiskCreateOptionTypes fromValue(final String text) {
+         return (DiskCreateOptionTypes) GetEnumValue.fromValueOrDefault(text, UNRECOGNIZED);
+      }
+
+      @Override
+      public String toString() {
+         return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name());
+      }
+   }
+   
+   public enum CachingTypes {
+      NONE,
+      READ_ONLY,
+      READ_WRITE,
+      UNRECOGNIZED;
+
+      public static CachingTypes fromValue(final String text) {
+         return (CachingTypes) GetEnumValue.fromValueOrDefault(text, UNRECOGNIZED);
+      }
+
+      @Override
+      public String toString() {
+         return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name());
+      }
+   }
 
    /**
     * The name of the data disk
     */
-   public abstract String name();
+   @Nullable public abstract String name();
 
    /**
     * The size of the data disk
     */
-   public abstract String diskSizeGB();
+   @Nullable public abstract String diskSizeGB();
 
    /**
     * The lun value of the data disk
     */
-   public abstract int lun();
+   @Nullable public abstract Integer lun();
 
    /**
     * The vhd of the data disk
     */
-   public abstract VHD vhd();
+   @Nullable public abstract VHD vhd();
+
+   /**
+    * The source user image virtual hard disk. This virtual hard disk will be
+    * copied before using it to attach to the virtual machine. If SourceImage
+    * is provided, the destination virtual hard disk must not exist.
+    */
+   @Nullable public abstract VHD image();
 
    /**
     * The create option of the data disk
     */
-   public abstract String createOption();
+   public abstract DiskCreateOptionTypes createOption();
+   
+   /**
+    * The caching type. Possible values include: 'None', 'ReadOnly',
+    * 'ReadWrite'.
+    */
+   @Nullable public abstract CachingTypes caching();
+
+   /**
+    * The managed disk parameters.
+    */
+   @Nullable public abstract ManagedDiskParameters managedDiskParameters();
+
+   @Nullable
+   public abstract String provisioningState();
 
-   @SerializedNames({"name", "diskSizeGB", "lun", "vhd", "createOption"})
-   public static DataDisk create(final String name, final String diskSizeGB, final int lun,
-                                 final VHD vhd, final String createOption) {
+   @SerializedNames({"name", "diskSizeGB", "lun", "vhd", "image", "createOption", "caching", "managedDisk", "provisioningState"})
+   public static DataDisk create(final String name, final String diskSizeGB, final Integer lun,
+                                 final VHD vhd, final VHD image, final String createOption, final String caching, 
+                                 final ManagedDiskParameters managedDiskParamenters, final String provisioningState) {
       return builder()
               .name(name)
               .diskSizeGB(diskSizeGB)
               .lun(lun)
-              .createOption(createOption)
               .vhd(vhd)
+              .image(image)
+              .caching(CachingTypes.fromValue(caching))
+              .createOption(DiskCreateOptionTypes.fromValue(createOption))
+              .managedDiskParameters(managedDiskParamenters)
+              .provisioningState(provisioningState)
               .build();
    }
    
@@ -68,16 +129,25 @@ public abstract class DataDisk {
 
    @AutoValue.Builder
    public abstract static class Builder {
+      
       public abstract Builder name(String name);
 
       public abstract Builder diskSizeGB(String diskSizeGB);
 
-      public abstract Builder createOption(String createOption);
+      public abstract Builder createOption(DiskCreateOptionTypes createOption);
 
-      public abstract Builder lun(int lun);
+      public abstract Builder lun(Integer lun);
 
       public abstract Builder vhd(VHD vhd);
 
+      public abstract Builder image(VHD image);
+
+      public abstract Builder caching(CachingTypes caching);
+
+      public abstract Builder managedDiskParameters(ManagedDiskParameters managedDiskParameters);
+      
+      public abstract Builder provisioningState(String provisioningState);
+
       public abstract DataDisk build();
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/37dcb87d/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Disk.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Disk.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Disk.java
new file mode 100644
index 0000000..c090aa8
--- /dev/null
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Disk.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.azurecompute.arm.domain;
+
+import java.util.Map;
+
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableMap;
+
+@AutoValue
+public abstract class Disk {
+
+   /**
+    * The id of the disk
+    */
+   @Nullable public abstract String id();
+   
+   /**
+    * The name of the disk
+    */
+   @Nullable public abstract String name();
+
+   /**
+    * The location of the disk
+    */
+   public abstract String location();
+
+   /**
+    * The type of the disk
+    */
+   @Nullable public abstract String type();
+
+   /**
+    * The sku of the disk
+    */
+   @Nullable public abstract SKU sku();
+
+   /**
+    * The managed disk parameters.
+    */
+   public abstract DiskProperties properties();
+   
+   /**
+    * the tags of the disk
+    */
+   @Nullable public abstract Map<String, String> tags();
+
+   @SerializedNames({"id", "name", "location", "type", "sku", "properties", "tags"})
+   public static Disk create(final String id, final String name, final String location,
+                             final String type, final SKU sku, 
+                             final DiskProperties properties, final Map<String, String> tags) {
+      return builder()
+              .id(id)
+              .name(name)
+              .location(location)
+              .type(type)
+              .sku(sku)
+              .properties(properties)
+              .tags(tags)
+              .build();
+   }
+
+   public abstract Builder toBuilder();
+
+   public static Builder builder() {
+      return new AutoValue_Disk.Builder();
+   }
+
+   @AutoValue.Builder
+   public abstract static class Builder {
+      public abstract Builder id(String id);
+      public abstract Builder name(String name);
+      public abstract Builder location(String location);
+      public abstract Builder type(String type);
+      public abstract Builder sku(SKU sku);
+      public abstract Builder properties(DiskProperties properties);
+      public abstract Builder tags(Map<String, String> tags);
+
+      abstract Map<String, String> tags();
+      abstract Disk autoBuild();
+
+      public Disk build() {
+         tags(tags() != null ? ImmutableMap.copyOf(tags()) : null);
+         return autoBuild();
+      }
+      
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/37dcb87d/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DiskProperties.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DiskProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DiskProperties.java
new file mode 100644
index 0000000..bcc62ca
--- /dev/null
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DiskProperties.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.azurecompute.arm.domain;
+
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+
+@AutoValue
+public abstract class DiskProperties implements Provisionable {
+
+   @Nullable
+   public abstract String provisioningState();
+   
+   @Nullable
+   public abstract String timeCreated();
+   
+   @Nullable
+   public abstract String diskState();
+
+   @Nullable
+   public abstract Integer diskSizeGB();
+   
+   @Nullable
+   public abstract Integer lun();
+
+   @Nullable
+   public abstract VHD vhd();
+
+   public abstract CreationData creationData();
+   
+   @SerializedNames({"provisioningState", "timeCreated", "diskState", "diskSizeGB", "lun", "vhd", "creationData"})
+   public static DiskProperties create(final String provisioningState, final String timeCreated, final String diskState, final Integer diskSizeGB, final Integer lun, final VHD vhd, final CreationData creationData) {
+      return builder()
+              .provisioningState(provisioningState)
+              .timeCreated(timeCreated)
+              .diskState(diskState)
+              .diskSizeGB(diskSizeGB)
+              .lun(lun)
+              .vhd(vhd)
+              .creationData(creationData)
+              .build();
+   }
+
+   public abstract Builder toBuilder();
+
+   public static Builder builder() {
+      return new AutoValue_DiskProperties.Builder();
+   }
+
+   @AutoValue.Builder
+   public abstract static class Builder {
+      public abstract Builder provisioningState(String provisioningState);
+      public abstract Builder timeCreated(String timeCreated);
+      public abstract Builder diskState(String diskState);
+      public abstract Builder diskSizeGB(Integer diskSizeGB);
+      public abstract Builder lun(Integer lun);
+      public abstract Builder vhd(VHD vhd);
+      public abstract Builder creationData(CreationData creationData);
+      public abstract DiskProperties build();
+
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/37dcb87d/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Image.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Image.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Image.java
new file mode 100644
index 0000000..5d9226b
--- /dev/null
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Image.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.azurecompute.arm.domain;
+
+import java.util.Map;
+
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableMap;
+
+@AutoValue
+public abstract class Image {
+
+   /**
+    * The location of the image
+    */
+   public abstract String location();
+
+   /**
+    * The image properties.
+    */
+   public abstract ImageProperties properties();
+
+   /**
+    * the tags of the image
+    */
+   @Nullable public abstract Map<String, String> tags();
+
+   @SerializedNames({"location", "properties", "tags"})
+   public static Image create(final String location, final ImageProperties properties, final Map<String, String> tags) {
+      return builder().location(location).properties(properties).tags(tags).build();
+   }
+
+   public abstract Builder toBuilder();
+
+   public static Builder builder() {
+      return new AutoValue_Image.Builder();
+   }
+
+   @AutoValue.Builder
+   public abstract static class Builder {
+      public abstract Builder location(String location);
+
+      public abstract Builder properties(ImageProperties properties);
+
+      public abstract Builder tags(Map<String, String> tags);
+
+      abstract Map<String, String> tags();
+
+      abstract Image autoBuild();
+
+      public Image build() {
+         tags(tags() != null ? ImmutableMap.copyOf(tags()) : null);
+         return autoBuild();
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/37dcb87d/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageProperties.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageProperties.java
new file mode 100644
index 0000000..ef877be
--- /dev/null
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageProperties.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.azurecompute.arm.domain;
+
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+
+@AutoValue
+public abstract class ImageProperties implements Provisionable {
+
+   @AutoValue
+   public abstract static class SourceVirtualMachine {
+      public abstract String id();
+
+      @SerializedNames({"id"})
+      public static SourceVirtualMachine create(final String id) {
+         return new AutoValue_ImageProperties_SourceVirtualMachine(id);
+      }
+   }
+   
+   public abstract SourceVirtualMachine sourceVirtualMachine();
+   
+   @Nullable
+   public abstract StorageProfile storageProfile();
+
+   @Nullable
+   public abstract String provisioningState();
+   
+   @SerializedNames({ "sourceVirtualMachine", "storageProfile", "provisioningState"})
+   public static ImageProperties create(final SourceVirtualMachine sourceVirtualMachine, 
+                                        final StorageProfile storageProfile,
+                                        final String provisioningState) {
+      return builder()
+              .sourceVirtualMachine(sourceVirtualMachine)
+              .storageProfile(storageProfile)
+              .provisioningState(provisioningState)
+              .build();
+   }
+
+   public abstract Builder toBuilder();
+
+   public static Builder builder() {
+      return new AutoValue_ImageProperties.Builder();
+   }
+
+   @AutoValue.Builder
+   public abstract static class Builder {
+      public abstract Builder sourceVirtualMachine(SourceVirtualMachine sourceVirtualMachine);
+      public abstract Builder storageProfile(StorageProfile storageProfile);
+      public abstract Builder provisioningState(String provisioningState);
+      public abstract ImageProperties build();
+
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/37dcb87d/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java
index f9e1875..443e054 100644
--- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java
@@ -16,15 +16,21 @@
  */
 package org.jclouds.azurecompute.arm.domain;
 
-import com.google.auto.value.AutoValue;
-
 import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.json.SerializedNames;
 
+import com.google.auto.value.AutoValue;
+
 @AutoValue
 public abstract class ImageReference {
 
    /**
+    * The id of the image reference.
+    */
+   @Nullable
+   public abstract String id();
+   
+   /**
     * The publisher of the image reference.
     */
    @Nullable
@@ -48,13 +54,15 @@ public abstract class ImageReference {
    @Nullable
    public abstract String version();
 
-   @SerializedNames({"publisher", "offer", "sku", "version"})
-   public static ImageReference create(final String publisher,
+   @SerializedNames({"id", "publisher", "offer", "sku", "version"})
+   public static ImageReference create(final String id,
+                                       final String publisher,
                                        final String offer,
                                        final String sku,
                                        final String version) {
 
       return builder()
+              .id(id)
               .publisher(publisher)
               .offer(offer)
               .sku(sku)
@@ -70,12 +78,10 @@ public abstract class ImageReference {
 
    @AutoValue.Builder
    public abstract static class Builder {
+      public abstract Builder id(String id);
       public abstract Builder publisher(String publisher);
-
       public abstract Builder offer(String offer);
-
       public abstract Builder sku(String sku);
-
       public abstract Builder version(String version);
 
       public abstract ImageReference build();

http://git-wip-us.apache.org/repos/asf/jclouds/blob/37dcb87d/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ManagedDiskParameters.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ManagedDiskParameters.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ManagedDiskParameters.java
new file mode 100644
index 0000000..84cbab1
--- /dev/null
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ManagedDiskParameters.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.azurecompute.arm.domain;
+
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+
+@AutoValue
+public abstract class ManagedDiskParameters {
+
+   public enum StorageAccountTypes {
+      /** Enum value Standard_LRS. */
+      STANDARD_LRS("Standard_LRS"),
+
+      /** Enum value Premium_LRS. */
+      PREMIUM_LRS("Premium_LRS");
+
+      /** The actual serialized value for a StorageAccountTypes instance. */
+      private String value;
+
+      StorageAccountTypes(String value) {
+         this.value = value;
+      }
+
+      public static StorageAccountTypes fromString(String value) {
+         StorageAccountTypes[] items = StorageAccountTypes.values();
+         for (StorageAccountTypes item : items) {
+            if (item.toString().equalsIgnoreCase(value)) {
+               return item;
+            }
+         }
+         return null;
+      }
+
+      @Override
+      public String toString() {
+         return this.value;
+      }
+   }
+
+   @Nullable public abstract String id();
+
+   public abstract StorageAccountTypes storageAccountType();
+
+   @SerializedNames({"id", "storageAccountType"})
+   public static ManagedDiskParameters create(final String id, final String storageAccountType) {
+      return new AutoValue_ManagedDiskParameters(id, StorageAccountTypes.fromString(storageAccountType));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/37dcb87d/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java
index 9cdee44..c87fe75 100644
--- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java
@@ -16,11 +16,11 @@
  */
 package org.jclouds.azurecompute.arm.domain;
 
-import com.google.auto.value.AutoValue;
-
 import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.json.SerializedNames;
 
+import com.google.auto.value.AutoValue;
+
 @AutoValue
 public abstract class OSDisk {
    /**
@@ -59,9 +59,15 @@ public abstract class OSDisk {
    @Nullable
    public abstract VHD image();
 
-   @SerializedNames({"osType", "name", "vhd", "caching", "createOption", "image"})
+   /**
+    * The managed disk parameters.
+    */
+   @Nullable public abstract ManagedDiskParameters managedDiskParameters();
+   
+   @SerializedNames({"osType", "name", "vhd", "caching", "createOption", "image", "managedDisk"})
    public static OSDisk create(final String osType, final String name, final VHD vhd,
-                               final String caching, final String createOption, final VHD image) {
+                               final String caching, final String createOption, final VHD image, 
+                               final ManagedDiskParameters managedDiskParamenters) {
       return builder()
             .osType(osType)
             .name(name)
@@ -69,7 +75,8 @@ public abstract class OSDisk {
             .caching(caching)
             .createOption(createOption)
             .image(image)
-            .build();
+              .managedDiskParameters(managedDiskParamenters)
+              .build();
    }
    
    public abstract Builder toBuilder();
@@ -86,6 +93,7 @@ public abstract class OSDisk {
       public abstract Builder createOption(String createOption);
       public abstract Builder vhd(VHD vhd);
       public abstract Builder image(VHD image);
+      public abstract Builder managedDiskParameters(ManagedDiskParameters managedDiskParameters);
       public abstract OSDisk build();
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/37dcb87d/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/DiskApi.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/DiskApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/DiskApi.java
new file mode 100644
index 0000000..0797dbd
--- /dev/null
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/DiskApi.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.azurecompute.arm.features;
+
+import java.net.URI;
+import java.util.List;
+
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
+import org.jclouds.Fallbacks.NullOnNotFoundOr404;
+import org.jclouds.azurecompute.arm.domain.Disk;
+import org.jclouds.azurecompute.arm.domain.DiskProperties;
+import org.jclouds.azurecompute.arm.filters.ApiVersionFilter;
+import org.jclouds.azurecompute.arm.functions.URIParser;
+import org.jclouds.oauth.v2.filters.OAuthFilter;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.MapBinder;
+import org.jclouds.rest.annotations.Payload;
+import org.jclouds.rest.annotations.PayloadParam;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.SelectJson;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+@Path("/resourcegroups/{resourcegroup}/providers/Microsoft.Compute/disks")
+@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class })
+@Consumes(MediaType.APPLICATION_JSON)
+public interface DiskApi {
+
+   @Named("disk:list")
+   @SelectJson("value")
+   @GET
+   @Fallback(EmptyListOnNotFoundOr404.class)
+   List<Disk> list();
+
+   @Named("disk:create_or_update")
+   @PUT
+   @Payload("%7B\"location\":\"{location}\",\"properties\":{properties}%7D")
+   @MapBinder(BindToJsonPayload.class)
+   @Path("/{diskName}")
+   @Produces(MediaType.APPLICATION_JSON)
+   Disk createOrUpdate(@PathParam("diskName") String diskName,
+                       @PayloadParam("location") String location,
+                       @PayloadParam("properties") DiskProperties properties);
+
+   @Named("disk:get")
+   @Path("/{diskName}")
+   @GET
+   @Fallback(NullOnNotFoundOr404.class)
+   Disk get(@PathParam("diskName") String diskName);
+
+   @Named("disk:delete")
+   @Path("/{diskName}")
+   @DELETE
+   @ResponseParser(URIParser.class)
+   @Fallback(NullOnNotFoundOr404.class)
+   URI delete(@PathParam("diskName") String diskName);
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/37dcb87d/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ImageApi.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ImageApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ImageApi.java
new file mode 100644
index 0000000..c97b0ac
--- /dev/null
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ImageApi.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.azurecompute.arm.features;
+
+import java.net.URI;
+import java.util.List;
+
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
+import org.jclouds.Fallbacks.NullOnNotFoundOr404;
+import org.jclouds.azurecompute.arm.domain.Image;
+import org.jclouds.azurecompute.arm.domain.ImageProperties;
+import org.jclouds.azurecompute.arm.filters.ApiVersionFilter;
+import org.jclouds.azurecompute.arm.functions.URIParser;
+import org.jclouds.oauth.v2.filters.OAuthFilter;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.MapBinder;
+import org.jclouds.rest.annotations.Payload;
+import org.jclouds.rest.annotations.PayloadParam;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.SelectJson;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+@Path("/resourcegroups/{resourcegroup}/providers/Microsoft.Compute/images")
+@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class })
+@Consumes(MediaType.APPLICATION_JSON)
+public interface ImageApi {
+
+   @Named("image:list")
+   @SelectJson("value")
+   @GET
+   @Fallback(EmptyListOnNotFoundOr404.class)
+   List<Image> list();
+
+   @Named("image:create_or_update")
+   @PUT
+   @Payload("%7B\"location\":\"{location}\",\"properties\":{properties}%7D")
+   @MapBinder(BindToJsonPayload.class)
+   @Path("/{imageName}")
+   @Produces(MediaType.APPLICATION_JSON)
+   Image createOrUpdate(@PathParam("imageName") String imageName,
+                       @PayloadParam("location") String location,
+                       @PayloadParam("properties") ImageProperties properties);
+
+   @Named("image:get")
+   @Path("/{imageName}")
+   @GET
+   @Fallback(NullOnNotFoundOr404.class)
+   Image get(@PathParam("imageName") String imageName);
+
+   @Named("image:delete")
+   @Path("/{imageName}")
+   @DELETE
+   @ResponseParser(URIParser.class)
+   @Fallback(NullOnNotFoundOr404.class)
+   URI delete(@PathParam("imageName") String imageName);
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/37dcb87d/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/OSImageApi.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/OSImageApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/OSImageApi.java
index 50c5c45..32b3ccc 100644
--- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/OSImageApi.java
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/OSImageApi.java
@@ -16,8 +16,6 @@
  */
 package org.jclouds.azurecompute.arm.features;
 
-import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
-
 import java.util.List;
 
 import javax.inject.Named;
@@ -36,6 +34,8 @@ import org.jclouds.oauth.v2.filters.OAuthFilter;
 import org.jclouds.rest.annotations.Fallback;
 import org.jclouds.rest.annotations.RequestFilters;
 
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
 /**
  * The Azure Resource Management API includes operations for managing the OS images in your subscription.
  */
@@ -90,4 +90,5 @@ public interface OSImageApi {
    @Fallback(EmptyListOnNotFoundOr404.class)
    Version getVersion(@PathParam("publisher") String publisher, @PathParam("offer") String offer,
                           @PathParam("sku") String sku, @PathParam("version") String version);
+
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/37dcb87d/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/VMImages.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/VMImages.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/VMImages.java
new file mode 100644
index 0000000..d5b6394
--- /dev/null
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/VMImages.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.azurecompute.arm.util;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class VMImages {
+
+   public static boolean isCustom(String imageId) {
+      return checkNotNull(imageId, "id").split("/").length == 5;
+   }
+  
+}