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 2016/10/18 13:07:52 UTC

[1/3] jclouds-labs git commit: Configure jclouds group in virtualmachine tags

Repository: jclouds-labs
Updated Branches:
  refs/heads/master 7fe205f0b -> 2e3874301


Configure jclouds group in virtualmachine tags


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

Branch: refs/heads/master
Commit: 3e5c92d9f3b859ad9d13f76c4894b7322962e891
Parents: f6e1134
Author: Ignasi Barrera <na...@apache.org>
Authored: Tue Oct 18 11:17:38 2016 +0200
Committer: Ignasi Barrera <na...@apache.org>
Committed: Tue Oct 18 12:09:07 2016 +0200

----------------------------------------------------------------------
 .../arm/compute/AzureComputeServiceAdapter.java           | 10 +++++++---
 .../compute/functions/VirtualMachineToNodeMetadata.java   |  8 +++++++-
 2 files changed, 14 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/3e5c92d9/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java
index 4574ca7..9670433 100644
--- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java
+++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java
@@ -99,6 +99,8 @@ import com.google.common.collect.Lists;
 @Singleton
 public class AzureComputeServiceAdapter implements ComputeServiceAdapter<VirtualMachine, VMHardware, VMImage, Location> {
 
+   public static final String GROUP_KEY = "jclouds_group";
+   
    private final CleanupResources cleanupResources;
    private final AzureComputeApi api;
    private final AzureComputeConstants azureComputeConstants;
@@ -125,8 +127,6 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual
       AzureTemplateOptions templateOptions = template.getOptions().as(AzureTemplateOptions.class);
       String azureGroup = locationToResourceGroupName.apply(template.getLocation().getId());
 
-      // TODO Store group apart from the name to be able to identify nodes with
-      // custom names in the configured group
       // TODO ARM specific options
       // TODO network ids => create one nic in each network
       // TODO inbound ports
@@ -145,6 +145,9 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual
             .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);
       Map<String, String> metadataAndTags = metadataAndTagsAsCommaDelimitedValue(template.getOptions());
       Plan plan = getMarketplacePlanFromImageMetadata(template.getImage());
 
@@ -187,7 +190,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(version.properties()).build();
+                     .version(versionDetails.name()).location(location).versionProperties(versionDetails.properties())
+                     .build();
                osImagesRef.add(vmImage);
             }
          }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/3e5c92d9/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VirtualMachineToNodeMetadata.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VirtualMachineToNodeMetadata.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VirtualMachineToNodeMetadata.java
index 48c8508..6527d25 100644
--- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VirtualMachineToNodeMetadata.java
+++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VirtualMachineToNodeMetadata.java
@@ -20,6 +20,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.collect.Iterables.find;
 import static com.google.common.collect.Iterables.transform;
 import static com.google.common.collect.Iterables.tryFind;
+import static org.jclouds.azurecompute.arm.compute.AzureComputeServiceAdapter.GROUP_KEY;
 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.encodeFieldsToUniqueId;
@@ -148,7 +149,6 @@ public class VirtualMachineToNodeMetadata implements Function<VirtualMachine, No
       builder.providerId(virtualMachine.id());
       builder.name(virtualMachine.name());
       builder.hostname(virtualMachine.name());
-      builder.group(nodeNamingConvention.extractGroup(virtualMachine.name()));
 
       ProvisioningState provisioningState = virtualMachine.properties().provisioningState();
       if (ProvisioningState.SUCCEEDED.equals(provisioningState)) {
@@ -175,10 +175,16 @@ public class VirtualMachineToNodeMetadata implements Function<VirtualMachine, No
       builder.publicAddresses(getPublicIpAddresses(virtualMachine.properties().networkProfile().networkInterfaces()));
       builder.privateAddresses(getPrivateIpAddresses(virtualMachine.properties().networkProfile().networkInterfaces()));
 
+      String groupFromMetadata = null;
       if (virtualMachine.tags() != null) {
          addMetadataAndParseTagsFromCommaDelimitedValue(builder, virtualMachine.tags());
+         groupFromMetadata = virtualMachine.tags().get(GROUP_KEY);
       }
       
+      // Try to read the group from the virtual machine tags, and parse the name if missing
+      builder.group(groupFromMetadata != null ? groupFromMetadata : nodeNamingConvention.extractGroup(virtualMachine
+            .name()));
+      
       String locationName = virtualMachine.location();
       builder.location(getLocation(locationName));
 


[3/3] jclouds-labs git commit: Null guards

Posted by na...@apache.org.
Null guards


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

Branch: refs/heads/master
Commit: 2e3874301895557c366bc0c613605d68704f9305
Parents: 3e5c92d
Author: Ignasi Barrera <na...@apache.org>
Authored: Tue Oct 18 12:31:46 2016 +0200
Committer: Ignasi Barrera <na...@apache.org>
Committed: Tue Oct 18 12:32:08 2016 +0200

----------------------------------------------------------------------
 .../functions/VirtualMachineToNodeMetadata.java | 45 +++++++++++++-------
 1 file changed, 29 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2e387430/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VirtualMachineToNodeMetadata.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VirtualMachineToNodeMetadata.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VirtualMachineToNodeMetadata.java
index 6527d25..5e98fbf 100644
--- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VirtualMachineToNodeMetadata.java
+++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VirtualMachineToNodeMetadata.java
@@ -156,14 +156,19 @@ public class VirtualMachineToNodeMetadata implements Function<VirtualMachine, No
          // the VM
          VirtualMachineInstance instanceDetails = api.getVirtualMachineApi(azureGroup).getInstanceDetails(
                virtualMachine.name());
-         builder.status(POWERSTATE_TO_NODESTATUS.apply(instanceDetails.powerState()));
-         builder.backendStatus(Joiner.on(',').join(
-               transform(instanceDetails.statuses(), new Function<VirtualMachineStatus, String>() {
-                  @Override
-                  public String apply(VirtualMachineStatus input) {
-                     return input.code();
-                  }
-               })));
+         if (instanceDetails != null && instanceDetails.powerState() != null) {
+            builder.status(POWERSTATE_TO_NODESTATUS.apply(instanceDetails.powerState()));
+            builder.backendStatus(Joiner.on(',').join(
+                  transform(instanceDetails.statuses(), new Function<VirtualMachineStatus, String>() {
+                     @Override
+                     public String apply(VirtualMachineStatus input) {
+                        return input.code();
+                     }
+                  })));
+         } else {
+            builder.status(NodeMetadata.Status.PENDING);
+            builder.backendStatus(provisioningState.name());
+         }
       } else {
          builder.status(PROVISIONINGSTATE_TO_NODESTATUS.apply(provisioningState));
          builder.backendStatus(provisioningState.name());
@@ -207,8 +212,13 @@ public class VirtualMachineToNodeMetadata implements Function<VirtualMachine, No
       List<String> privateIpAddresses = Lists.newArrayList();
       for (IdReference networkInterfaceCardIdReference : idReferences) {
          NetworkInterfaceCard networkInterfaceCard = getNetworkInterfaceCard(networkInterfaceCardIdReference);
-         for (IpConfiguration ipConfiguration : networkInterfaceCard.properties().ipConfigurations()) {
-            privateIpAddresses.add(ipConfiguration.properties().privateIPAddress());
+         if (networkInterfaceCard != null && networkInterfaceCard.properties() != null
+               && networkInterfaceCard.properties().ipConfigurations() != null) {
+            for (IpConfiguration ipConfiguration : networkInterfaceCard.properties().ipConfigurations()) {
+               if (ipConfiguration.properties().privateIPAddress() != null) {
+                  privateIpAddresses.add(ipConfiguration.properties().privateIPAddress());
+               }
+            }
          }
       }
       return privateIpAddresses;
@@ -226,12 +236,15 @@ public class VirtualMachineToNodeMetadata implements Function<VirtualMachine, No
       List<String> publicIpAddresses = Lists.newArrayList();
       for (IdReference networkInterfaceCardIdReference : idReferences) {
          NetworkInterfaceCard networkInterfaceCard = getNetworkInterfaceCard(networkInterfaceCardIdReference);
-         String resourceGroup = Iterables.get(Splitter.on("/").split(networkInterfaceCardIdReference.id()), 4);
-         for (IpConfiguration ipConfiguration : networkInterfaceCard.properties().ipConfigurations()) {
-            if (ipConfiguration.properties().publicIPAddress() != null) {
-               String publicIpId = ipConfiguration.properties().publicIPAddress().id();
-               publicIpAddresses.add(api.getPublicIPAddressApi(resourceGroup)
-                     .get(Iterables.getLast(Splitter.on("/").split(publicIpId))).properties().ipAddress());
+         if (networkInterfaceCard != null && networkInterfaceCard.properties() != null
+               && networkInterfaceCard.properties().ipConfigurations() != null) {
+            String resourceGroup = Iterables.get(Splitter.on("/").split(networkInterfaceCardIdReference.id()), 4);
+            for (IpConfiguration ipConfiguration : networkInterfaceCard.properties().ipConfigurations()) {
+               if (ipConfiguration.properties().publicIPAddress() != null) {
+                  String publicIpId = ipConfiguration.properties().publicIPAddress().id();
+                  publicIpAddresses.add(api.getPublicIPAddressApi(resourceGroup)
+                        .get(Iterables.getLast(Splitter.on("/").split(publicIpId))).properties().ipAddress());
+               }
             }
          }
       }


[2/3] jclouds-labs git commit: Configuration to deploy VMs from the Marketplace

Posted by na...@apache.org.
Configuration to deploy VMs from the Marketplace


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

Branch: refs/heads/master
Commit: f6e11340832b606927a819f3e70e0620e324b99b
Parents: 7fe205f
Author: Ignasi Barrera <na...@apache.org>
Authored: Mon Oct 17 13:24:41 2016 +0200
Committer: Ignasi Barrera <na...@apache.org>
Committed: Tue Oct 18 12:09:07 2016 +0200

----------------------------------------------------------------------
 .../arm/compute/AzureComputeServiceAdapter.java |  13 +-
 .../arm/compute/functions/VMImageToImage.java   |  99 +++++++----
 .../jclouds/azurecompute/arm/domain/Plan.java   |  47 ++++++
 .../azurecompute/arm/domain/VMImage.java        |   8 +
 .../azurecompute/arm/domain/Version.java        |  51 +++++-
 .../azurecompute/arm/domain/VirtualMachine.java |  37 ++++-
 .../azurecompute/arm/features/OSImageApi.java   |  10 ++
 .../arm/features/VirtualMachineApi.java         |   7 +-
 .../arm/features/VirtualMachineApiLiveTest.java |   2 +-
 .../arm/features/VirtualMachineApiMockTest.java | 166 ++++++++++++-------
 .../resources/createvirtualmachineresponse.json |   5 +
 .../src/test/resources/virtualmachine.json      |   5 +
 12 files changed, 338 insertions(+), 112 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f6e11340/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java
index 8e4531d..4574ca7 100644
--- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java
+++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java
@@ -24,6 +24,7 @@ import static org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageE
 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.compute.util.ComputeServiceUtils.metadataAndTagsAsCommaDelimitedValue;
 import static org.jclouds.util.Closeables2.closeQuietly;
 
@@ -52,6 +53,7 @@ import org.jclouds.azurecompute.arm.domain.NetworkProfile;
 import org.jclouds.azurecompute.arm.domain.OSDisk;
 import org.jclouds.azurecompute.arm.domain.OSProfile;
 import org.jclouds.azurecompute.arm.domain.Offer;
+import org.jclouds.azurecompute.arm.domain.Plan;
 import org.jclouds.azurecompute.arm.domain.PublicIPAddress;
 import org.jclouds.azurecompute.arm.domain.PublicIPAddressProperties;
 import org.jclouds.azurecompute.arm.domain.RegionAndId;
@@ -144,9 +146,10 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual
             .networkProfile(networkProfile).build();
       
       Map<String, String> metadataAndTags = metadataAndTagsAsCommaDelimitedValue(template.getOptions());
+      Plan plan = getMarketplacePlanFromImageMetadata(template.getImage());
 
       VirtualMachine virtualMachine = api.getVirtualMachineApi(azureGroup).create(name, template.getLocation().getId(),
-            virtualMachineProperties, metadataAndTags);
+            virtualMachineProperties, metadataAndTags, plan);
 
       // Safe to pass null credentials here, as jclouds will default populate
       // the node with the default credentials from the image, or the ones in
@@ -182,8 +185,9 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual
          for (SKU sku : skuList) {
             Iterable<Version> versionList = osImageApi.listVersions(publisherName, offer.name(), sku.name());
             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(version.name()).location(location).build();
+                     .version(versionDetails.name()).location(location).versionProperties(version.properties()).build();
                osImagesRef.add(vmImage);
             }
          }
@@ -275,8 +279,9 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual
       OSImageApi osImageApi = api.getOSImageApi(location);
       List<Version> versions = osImageApi.listVersions(publisher, offer, sku);
       if (!versions.isEmpty()) {
-         return VMImage.azureImage().publisher(publisher).offer(offer).sku(sku).version(versions.get(0).name())
-               .location(location).build();
+         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();
       }
       return null;
    }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f6e11340/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java
index 9d9eceb..f037cfe 100644
--- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java
+++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java
@@ -16,9 +16,13 @@
  */
 package org.jclouds.azurecompute.arm.compute.functions;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
 import java.util.Set;
 
 import org.jclouds.azurecompute.arm.domain.ImageReference;
+import org.jclouds.azurecompute.arm.domain.Plan;
 import org.jclouds.azurecompute.arm.domain.VMImage;
 import org.jclouds.collect.Memoized;
 import org.jclouds.compute.domain.Image;
@@ -26,17 +30,19 @@ import org.jclouds.compute.domain.ImageBuilder;
 import org.jclouds.compute.domain.OperatingSystem;
 import org.jclouds.compute.domain.OsFamily;
 import org.jclouds.domain.Location;
+import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.location.predicates.LocationPredicates;
 
 import com.google.common.base.Function;
 import com.google.common.base.Supplier;
 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;
-
 public class VMImageToImage implements Function<VMImage, Image> {
 
+   public static final String MARKETPLACE_TAG = "marketplace";
+
    private static final String UBUNTU = "Ubuntu";
    private static final String WINDOWS = "Windows";
    private static final String OPENLOGIC = "openLogic";
@@ -50,16 +56,20 @@ public class VMImageToImage implements Function<VMImage, Image> {
 
    private final Supplier<Set<? extends org.jclouds.domain.Location>> locations;
 
-   public static String encodeFieldsToUniqueId(boolean globallyAvailable, String locatioName, ImageReference imageReference){
-      return (globallyAvailable ? "global" : locatioName) + "/" + imageReference.publisher() + "/" + imageReference.offer() + "/" + imageReference.sku();
+   public static String encodeFieldsToUniqueId(boolean globallyAvailable, String locatioName,
+         ImageReference imageReference) {
+      return (globallyAvailable ? "global" : locatioName) + "/" + imageReference.publisher() + "/"
+            + imageReference.offer() + "/" + imageReference.sku();
    }
-   
-   public static String encodeFieldsToUniqueId(VMImage imageReference){
-      return (imageReference.globallyAvailable() ? "global" : imageReference.location()) + "/" + imageReference.publisher() + "/" + imageReference.offer() + "/" + imageReference.sku();
+
+   public static String encodeFieldsToUniqueId(VMImage imageReference) {
+      return (imageReference.globallyAvailable() ? "global" : imageReference.location()) + "/"
+            + imageReference.publisher() + "/" + imageReference.offer() + "/" + imageReference.sku();
    }
 
-   public static String encodeFieldsToUniqueIdCustom(VMImage imageReference){
-      return (imageReference.globallyAvailable() ? "global" : imageReference.location()) + "/" + imageReference.group() + "/" + imageReference.storage() + "/" + imageReference.offer() + "/" + imageReference.name();
+   public static String encodeFieldsToUniqueIdCustom(VMImage imageReference) {
+      return (imageReference.globallyAvailable() ? "global" : imageReference.location()) + "/" + imageReference.group()
+            + "/" + imageReference.storage() + "/" + imageReference.offer() + "/" + imageReference.name();
    }
 
    public static VMImage decodeFieldsFromUniqueId(final String id) {
@@ -74,7 +84,8 @@ public class VMImageToImage implements Function<VMImage, Image> {
          3: imageReference.offer + "/" +
          4: imageReference.name
          */
-         vmImage = VMImage.customImage().location(fields[0]).group(fields[1]).storage(fields[2]).vhd1(fields[3]).offer(fields[4]).build();
+         vmImage = VMImage.customImage().location(fields[0]).group(fields[1]).storage(fields[2]).vhd1(fields[3])
+               .offer(fields[4]).build();
       } else {
          /* id fields indexes
          0: imageReference.location) + "/" +
@@ -82,7 +93,8 @@ public class VMImageToImage implements Function<VMImage, Image> {
          2: imageReference.offer + "/" +
          3: imageReference.sku + "/" +
          */
-         vmImage = VMImage.azureImage().location(fields[0]).publisher(fields[1]).offer(fields[2]).sku(fields[3]).build();
+         vmImage = VMImage.azureImage().location(fields[0]).publisher(fields[1]).offer(fields[2]).sku(fields[3])
+               .build();
       }
       return vmImage;
    }
@@ -94,38 +106,50 @@ public class VMImageToImage implements Function<VMImage, Image> {
 
    @Override
    public Image apply(final VMImage image) {
+      final ImageBuilder builder = new ImageBuilder();
+      addMarketplacePlanToMetadataIfPresent(builder, image);
       if (image.custom()) {
-         final ImageBuilder builder = new ImageBuilder()
-               .location(FluentIterable.from(locations.get())
-                     .firstMatch(LocationPredicates.idEquals(image.location()))
-                     .get())
-               .name(image.name())
-               .description(image.group())
-               .status(Image.Status.AVAILABLE)
-               .version("latest")
-               .providerId(image.vhd1())
-               .id(encodeFieldsToUniqueIdCustom(image));
+         builder.location(
+                     FluentIterable.from(locations.get()).firstMatch(LocationPredicates.idEquals(image.location()))
+                           .get()).name(image.name()).description(image.group()).status(Image.Status.AVAILABLE)
+               .version("latest").providerId(image.vhd1()).id(encodeFieldsToUniqueIdCustom(image));
 
          final OperatingSystem.Builder osBuilder = osFamily().apply(image);
-         Image retimage = builder.operatingSystem(osBuilder.build()).build();
-         return retimage;
-      }
-      else {
-         final ImageBuilder builder = new ImageBuilder()
+         builder.operatingSystem(osBuilder.build());
+      } else {
+         builder
                .name(image.offer())
                .description(image.sku())
                .status(Image.Status.AVAILABLE)
                .version(image.sku())
                .id(encodeFieldsToUniqueId(image))
                .providerId(image.publisher())
-               .location(image.globallyAvailable() ? null : FluentIterable.from(locations.get())
-                     .firstMatch(LocationPredicates.idEquals(image.location()))
-                     .get());
+               .location(
+                     image.globallyAvailable() ? null : FluentIterable.from(locations.get())
+                           .firstMatch(LocationPredicates.idEquals(image.location())).get());
 
          final OperatingSystem.Builder osBuilder = osFamily().apply(image);
-         return builder.operatingSystem(osBuilder.build()).build();
+         builder.operatingSystem(osBuilder.build());
+      }
+      return builder.build();
+   }
+   
+   private static void addMarketplacePlanToMetadataIfPresent(ImageBuilder builder, VMImage image) {
+      if (image.versionProperties() != null && image.versionProperties().plan() != null) {
+         // Store the plan information in the metadata so the adapter can
+         // properly configure it when deploying images from the marketplace
+         Plan plan = image.versionProperties().plan();
+         builder.userMetadata(ImmutableMap.of("publisher", plan.publisher(), "name", plan.name(), "product",
+               plan.product()));
       }
    }
+   
+   @Nullable
+   public static Plan getMarketplacePlanFromImageMetadata(Image image) {
+      Map<String, String> imageMetadata = image.getUserMetadata();
+      return imageMetadata.containsKey("product") ? Plan.create(imageMetadata.get("publisher"),
+            imageMetadata.get("name"), imageMetadata.get("product")) : null;
+   }
 
    public static Function<VMImage, OperatingSystem.Builder> osFamily() {
       return new Function<VMImage, OperatingSystem.Builder>() {
@@ -150,13 +174,18 @@ public class VMImageToImage implements Function<VMImage, Image> {
             } else if (label.contains(RHEL)) {
                family = OsFamily.RHEL;
             }
+            
+            // Fallback to generic operating system type
+            if (OsFamily.UNRECOGNIZED == family && image.versionProperties() != null
+                  && image.versionProperties().osDiskImage() != null
+                  && image.versionProperties().osDiskImage().operatingSystem() != null) {
+               family = OsFamily.fromValue(image.versionProperties().osDiskImage().operatingSystem().toUpperCase());
+            }
 
             // only 64bit OS images are supported by Azure ARM
-            return OperatingSystem.builder().
-                  family(family).
-                  is64Bit(true).
-                  description(image.custom() ? image.vhd1() : image.sku()).
-                  version(image.custom() ? "latest" : image.sku());
+            return OperatingSystem.builder().family(family).is64Bit(true)
+                  .description(image.custom() ? image.vhd1() : image.sku())
+                  .version(image.custom() ? "latest" : image.sku());
          }
       };
    }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f6e11340/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Plan.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Plan.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Plan.java
new file mode 100644
index 0000000..6863146
--- /dev/null
+++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Plan.java
@@ -0,0 +1,47 @@
+/*
+ * 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.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+
+/**
+ * Plan
+ */
+@AutoValue
+public abstract class Plan {
+   /**
+    * The publisher of the Plan
+    */
+   public abstract String publisher();
+   
+   /**
+    * The name of the Plan
+    */
+   public abstract String name();
+   
+   /**
+    * The product of the Plan
+    */
+   public abstract String product();
+   
+   @SerializedNames({"publisher", "name", "product"})
+   public static Plan create(final String publisher, final String name, final String product) {
+      return new AutoValue_Plan(publisher, name, product);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f6e11340/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java
index e4f2301..b08355e 100644
--- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java
+++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java
@@ -16,6 +16,7 @@
  */
 package org.jclouds.azurecompute.arm.domain;
 
+import org.jclouds.azurecompute.arm.domain.Version.VersionProperties;
 import org.jclouds.javax.annotation.Nullable;
 
 import com.google.auto.value.AutoValue;
@@ -92,6 +93,12 @@ public abstract class VMImage {
     */
    public abstract boolean custom();
    
+   /**
+    * Extended version properties.
+    */
+   @Nullable
+   public abstract VersionProperties versionProperties();
+   
    public static Builder builder() {
       return new AutoValue_VMImage.Builder();
    }
@@ -119,6 +126,7 @@ public abstract class VMImage {
       public abstract Builder vhd2(String vhd2);
       public abstract Builder name(String name);
       public abstract Builder custom(boolean custom);
+      public abstract Builder versionProperties(VersionProperties versionProperties);
       
       public abstract VMImage build();
    }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f6e11340/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Version.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Version.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Version.java
index 63d7e11..26bf4b0 100644
--- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Version.java
+++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Version.java
@@ -16,9 +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;
+
 /**
  * Version
  */
@@ -39,11 +41,50 @@ public abstract class Version {
     * The id of the Version
     */
    public abstract String id();
+   
+   /**
+    * The plan for the Version if this image is from the marketplace.
+    */
+   @Nullable
+   public abstract VersionProperties properties();
+   
+   Version() {
+      
+   }
 
-   @SerializedNames({"location", "name", "id"})
-   public static Version create(final String location, final String name, final String id) {
-
-      return new AutoValue_Version(location, name, id);
+   @SerializedNames({"location", "name", "id", "properties"})
+   public static Version create(final String location, final String name, final String id,
+         final VersionProperties properties) {
+      return new AutoValue_Version(location, name, id, properties);
+   }
+   
+   @AutoValue
+   public abstract static class VersionProperties {
+      @Nullable public abstract Plan plan();
+      public abstract OSDiskImage osDiskImage();
+      
+      VersionProperties() {
+         
+      }
+      
+      @SerializedNames({"plan", "osDiskImage"})
+      public static VersionProperties create(Plan plan, OSDiskImage osDiskImage) {
+         return new AutoValue_Version_VersionProperties(plan, osDiskImage);
+      }
+      
+      @AutoValue
+      public abstract static class OSDiskImage {
+         public abstract String operatingSystem();
+         
+         OSDiskImage() {
+            
+         }
+         
+         @SerializedNames({"operatingSystem"})
+         public static OSDiskImage create(String operatingSystem) {
+            return new AutoValue_Version_VersionProperties_OSDiskImage(operatingSystem);
+         }
+      }
    }
 }
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f6e11340/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachine.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachine.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachine.java
index 10fa231..65a389c 100644
--- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachine.java
+++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachine.java
@@ -60,11 +60,42 @@ public abstract class VirtualMachine {
     * Specifies the properties of the vm
     */
    public abstract VirtualMachineProperties properties();
+   
+   /**
+    * Specifies the plan, for marketplace images
+    */
+   @Nullable
+   public abstract Plan plan();
 
-   @SerializedNames({"id", "name", "type", "location", "tags", "properties"})
+   @SerializedNames({"id", "name", "type", "location", "tags", "properties", "plan"})
    public static VirtualMachine create(final String id, final String name, final String type, final String location,
-                                       @Nullable final Map<String, String> tags, VirtualMachineProperties properties) {
+         @Nullable final Map<String, String> tags, VirtualMachineProperties properties, @Nullable Plan plan) {
+      return builder().id(id).name(name).type(type).location(location).tags(tags).properties(properties).plan(plan)
+            .build();
+   }
+   
+   public static Builder builder() {
+      return new AutoValue_VirtualMachine.Builder();
+   }
+   
+   @AutoValue.Builder
+   public abstract static class Builder {
+      
+      public abstract Builder id(String id);
+      public abstract Builder name(String name);
+      public abstract Builder type(String type);
+      public abstract Builder location(String location);
+      public abstract Builder tags(Map<String, String> tags);
+      public abstract Builder properties(VirtualMachineProperties properties);
+      public abstract Builder plan(Plan plan);
+      
+      abstract Map<String, String> tags();
+
+      abstract VirtualMachine autoBuild();
 
-      return new AutoValue_VirtualMachine(id, name, type, location, tags == null ? null : ImmutableMap.copyOf(tags), properties);
+      public VirtualMachine build() {
+         tags(tags() != null ? ImmutableMap.copyOf(tags()) : null);
+         return autoBuild();
+      }
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f6e11340/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/OSImageApi.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/OSImageApi.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/OSImageApi.java
index c8fb3f3..50c5c45 100644
--- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/OSImageApi.java
+++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/OSImageApi.java
@@ -80,4 +80,14 @@ public interface OSImageApi {
    @Fallback(EmptyListOnNotFoundOr404.class)
    List<Version> listVersions(@PathParam("publisher") String publisher, @PathParam("offer") String offer,
                           @PathParam("sku") String sku);
+   
+   /**
+    * Get the details of a Version
+    */
+   @Named("version:get")
+   @GET
+   @Path("/publishers/{publisher}/artifacttypes/vmimage/offers/{offer}/skus/{sku}/versions/{version}")
+   @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-labs/blob/f6e11340/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualMachineApi.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualMachineApi.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualMachineApi.java
index 2b44fa4..805378b 100644
--- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualMachineApi.java
+++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualMachineApi.java
@@ -32,11 +32,13 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 
 import org.jclouds.Fallbacks;
+import org.jclouds.azurecompute.arm.domain.Plan;
 import org.jclouds.azurecompute.arm.domain.VirtualMachine;
 import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance;
 import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties;
 import org.jclouds.azurecompute.arm.filters.ApiVersionFilter;
 import org.jclouds.azurecompute.arm.functions.URIParser;
+import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.oauth.v2.filters.OAuthFilter;
 import org.jclouds.rest.annotations.Fallback;
 import org.jclouds.rest.annotations.MapBinder;
@@ -81,7 +83,7 @@ public interface VirtualMachineApi {
     */
    @Named("CreateVirtualMachine")
    @PUT
-   @Payload("%7B\"location\":\"{location}\",\"tags\":{tags},\"properties\":{properties}%7D")
+   @Payload("%7B\"location\":\"{location}\",\"tags\":{tags},\"properties\":{properties},\"plan\":{plan}%7D")
    @MapBinder(BindToJsonPayload.class)
    @Path("/{vmname}")
    @QueryParams(keys = "validating", values = "false")
@@ -89,7 +91,8 @@ public interface VirtualMachineApi {
    VirtualMachine create(@PathParam("vmname") String vmname,
                          @PayloadParam("location") String location,
                          @PayloadParam("properties") VirtualMachineProperties properties,
-                         @PayloadParam("tags") Map<String, String> tags);
+                         @PayloadParam("tags") Map<String, String> tags,
+                         @Nullable @PayloadParam("plan") Plan plan);
 
    /**
     * The List Virtual Machines operation

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f6e11340/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineApiLiveTest.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineApiLiveTest.java b/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineApiLiveTest.java
index a0e2cbe..35ccd89 100644
--- a/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineApiLiveTest.java
+++ b/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineApiLiveTest.java
@@ -113,7 +113,7 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest {
       String blob = storageService.storageServiceProperties().primaryEndpoints().get("blob");
 
       VirtualMachine vm = api().create(vmName, LOCATION, getProperties(blob, nicName),
-            Collections.<String, String> emptyMap());
+            Collections.<String, String> emptyMap(), null);
       assertTrue(!vm.name().isEmpty());
 
       //Poll until resource is ready to be used

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f6e11340/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineApiMockTest.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineApiMockTest.java b/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineApiMockTest.java
index fd72344..5b034a0 100644
--- a/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineApiMockTest.java
+++ b/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineApiMockTest.java
@@ -37,6 +37,7 @@ import org.jclouds.azurecompute.arm.domain.ImageReference;
 import org.jclouds.azurecompute.arm.domain.NetworkProfile;
 import org.jclouds.azurecompute.arm.domain.OSDisk;
 import org.jclouds.azurecompute.arm.domain.OSProfile;
+import org.jclouds.azurecompute.arm.domain.Plan;
 import org.jclouds.azurecompute.arm.domain.StorageProfile;
 import org.jclouds.azurecompute.arm.domain.VHD;
 import org.jclouds.azurecompute.arm.domain.VirtualMachine;
@@ -55,16 +56,18 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest {
    public void testGet() throws Exception {
       server.enqueue(jsonResponse("/virtualmachine.json"));
       final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname");
-      assertEquals(vmAPI.get("windowsmachine"), getVM());
-      assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" +
-              "/virtualMachines/windowsmachine?api-version=2016-03-30");
+      assertEquals(vmAPI.get("windowsmachine"),
+            getVM(Plan.create("thinkboxsoftware", "deadline-slave-7-2", "deadline7-2")));
+      assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute"
+            + "/virtualMachines/windowsmachine?api-version=2016-03-30");
    }
+
    public void testGetEmpty() throws Exception {
       server.enqueue(new MockResponse().setResponseCode(404));
       final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname");
       assertNull(vmAPI.get("windowsmachine"));
-      assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" +
-              "/virtualMachines/windowsmachine?api-version=2016-03-30");
+      assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute"
+            + "/virtualMachines/windowsmachine?api-version=2016-03-30");
    }
 
    public void testGetInstanceDetails() throws Exception {
@@ -76,52 +79,80 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest {
       assertEquals(actual.statuses().get(0).code(), expected.statuses().get(0).code());
       assertEquals(actual.statuses().get(0).displayStatus(), expected.statuses().get(0).displayStatus());
       assertEquals(actual.statuses().get(0).level(), expected.statuses().get(0).level());
-      //assertEquals(actual.statuses().get(0).time().toString(), expected.statuses().get(0).time().toString());
-      assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" +
-              "/virtualMachines/windowsmachine/instanceView?api-version=2016-03-30");
+      // assertEquals(actual.statuses().get(0).time().toString(),
+      // expected.statuses().get(0).time().toString());
+      assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute"
+            + "/virtualMachines/windowsmachine/instanceView?api-version=2016-03-30");
    }
 
    public void testGetInstanceDetailsEmpty() throws Exception {
       server.enqueue(new MockResponse().setResponseCode(404));
       final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname");
       assertNull(vmAPI.getInstanceDetails("windowsmachine"));
-      assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" +
-              "/virtualMachines/windowsmachine/instanceView?api-version=2016-03-30");
+      assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute"
+            + "/virtualMachines/windowsmachine/instanceView?api-version=2016-03-30");
    }
 
    public void testList() throws Exception {
       server.enqueue(jsonResponse("/virtualmachines.json"));
       final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname");
       assertEquals(vmAPI.list(), getVMList());
-      assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" +
-              "/virtualMachines?api-version=2015-06-15");
+      assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute"
+            + "/virtualMachines?api-version=2015-06-15");
    }
+
    public void testListEmpty() throws Exception {
       server.enqueue(new MockResponse().setResponseCode(404));
       final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname");
       assertTrue(isEmpty(vmAPI.list()));
-      assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" +
-              "/virtualMachines?api-version=2015-06-15");
+      assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute"
+            + "/virtualMachines?api-version=2015-06-15");
    }
 
+   public void testCreateWithPlan() throws Exception {
+      server.enqueue(jsonResponse("/createvirtualmachineresponse.json"));
+      Plan plan = Plan.create("thinkboxsoftware", "deadline-slave-7-2", "deadline7-2");
+      final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname");
+      VirtualMachine vm = vmAPI
+            .create("windowsmachine", "westus", getProperties(), ImmutableMap.of("foo", "bar"), plan);
+      assertEquals(vm, getVM(plan));
+      assertSent(
+            server,
+            "PUT",
+            "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute"
+                  + "/virtualMachines/windowsmachine?validating=false&api-version=2016-03-30",
+            "{\"location\":\"westus\",\"tags\":{\"foo\":\"bar\"},\"properties\":"
+                  + "{\"vmId\":\"27ee085b-d707-xxxx-yyyy-2370e2eb1cc1\","
+                  + "\"hardwareProfile\":{\"vmSize\":\"Standard_D1\"},"
+                  + "\"storageProfile\":{\"imageReference\":{\"publisher\":\"publisher\",\"offer\":\"offer\",\"sku\":\"sku\",\"version\":\"ver\"},"
+                  + "\"osDisk\":{\"osType\":\"Windows\",\"name\":\"windowsmachine\","
+                  + "\"vhd\":{\"uri\":\"https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd\"},\"caching\":\"ReadWrite\",\"createOption\":\"FromImage\"},\"dataDisks\":[]},"
+                  + "\"osProfile\":{\"computerName\":\"windowsmachine\",\"adminUsername\":\"azureuser\",\"windowsConfiguration\":{\"provisionVMAgent\":false,\"enableAutomaticUpdates\":true}},"
+                  + "\"networkProfile\":{\"networkInterfaces\":[{\"id\":\"/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Network/networkInterfaces/windowsmachine167\"}]},"
+                  + "\"diagnosticsProfile\":{\"bootDiagnostics\":{\"enabled\":true,\"storageUri\":\"https://groupname2760.blob.core.windows.net/\"}},\"provisioningState\":\"CREATING\"},"
+                  + "\"plan\":{\"name\":\"deadline-slave-7-2\",\"publisher\":\"thinkboxsoftware\",\"product\":\"deadline7-2\"}}");
+   }
+   
    public void testCreate() throws Exception {
       server.enqueue(jsonResponse("/createvirtualmachineresponse.json"));
 
       final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname");
-      VirtualMachine vm = vmAPI.create("windowsmachine", "westus", getProperties(), ImmutableMap.of("foo", "bar"));
+      VirtualMachine vm = vmAPI.create("windowsmachine", "westus", getProperties(), ImmutableMap.of("foo", "bar"), null);
       assertEquals(vm, getVM());
-      assertSent(server, "PUT", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" +
-              "/virtualMachines/windowsmachine?validating=false&api-version=2016-03-30",
-              "{\"location\":\"westus\",\"tags\":{\"foo\":\"bar\"},\"properties\":" +
-                      "{\"vmId\":\"27ee085b-d707-xxxx-yyyy-2370e2eb1cc1\"," +
-                      "\"hardwareProfile\":{\"vmSize\":\"Standard_D1\"}," +
-                      "\"storageProfile\":{\"imageReference\":{\"publisher\":\"publisher\",\"offer\":\"offer\",\"sku\":\"sku\",\"version\":\"ver\"}," +
-                      "\"osDisk\":{\"osType\":\"Windows\",\"name\":\"windowsmachine\"," +
-                      "\"vhd\":{\"uri\":\"https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd\"},\"caching\":\"ReadWrite\",\"createOption\":\"FromImage\"},\"dataDisks\":[]}," +
-                      "\"osProfile\":{\"computerName\":\"windowsmachine\",\"adminUsername\":\"azureuser\",\"windowsConfiguration\":{\"provisionVMAgent\":false,\"enableAutomaticUpdates\":true}}," +
-                      "\"networkProfile\":{\"networkInterfaces\":[{\"id\":\"/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Network/networkInterfaces/windowsmachine167\"}]}," +
-                      "\"diagnosticsProfile\":{\"bootDiagnostics\":{\"enabled\":true,\"storageUri\":\"https://groupname2760.blob.core.windows.net/\"}},\"provisioningState\":\"CREATING\"}}");
-
+      assertSent(
+            server,
+            "PUT",
+            "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute"
+                  + "/virtualMachines/windowsmachine?validating=false&api-version=2016-03-30",
+            "{\"location\":\"westus\",\"tags\":{\"foo\":\"bar\"},\"properties\":"
+                  + "{\"vmId\":\"27ee085b-d707-xxxx-yyyy-2370e2eb1cc1\","
+                  + "\"hardwareProfile\":{\"vmSize\":\"Standard_D1\"},"
+                  + "\"storageProfile\":{\"imageReference\":{\"publisher\":\"publisher\",\"offer\":\"offer\",\"sku\":\"sku\",\"version\":\"ver\"},"
+                  + "\"osDisk\":{\"osType\":\"Windows\",\"name\":\"windowsmachine\","
+                  + "\"vhd\":{\"uri\":\"https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd\"},\"caching\":\"ReadWrite\",\"createOption\":\"FromImage\"},\"dataDisks\":[]},"
+                  + "\"osProfile\":{\"computerName\":\"windowsmachine\",\"adminUsername\":\"azureuser\",\"windowsConfiguration\":{\"provisionVMAgent\":false,\"enableAutomaticUpdates\":true}},"
+                  + "\"networkProfile\":{\"networkInterfaces\":[{\"id\":\"/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Network/networkInterfaces/windowsmachine167\"}]},"
+                  + "\"diagnosticsProfile\":{\"bootDiagnostics\":{\"enabled\":true,\"storageUri\":\"https://groupname2760.blob.core.windows.net/\"}},\"provisioningState\":\"CREATING\"}}");
    }
 
    public void testDeleteReturns404() throws Exception {
@@ -134,9 +165,10 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest {
       assertEquals(server.getRequestCount(), 1);
       assertNull(uri);
 
-      assertSent(server, "DELETE", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" +
-              "/virtualMachines/windowsmachine?api-version=2016-03-30");
+      assertSent(server, "DELETE", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute"
+            + "/virtualMachines/windowsmachine?api-version=2016-03-30");
    }
+
    public void testDelete() throws Exception {
       server.enqueue(response202WithHeader());
 
@@ -147,8 +179,8 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest {
       assertEquals(server.getRequestCount(), 1);
       assertNotNull(uri);
 
-      assertSent(server, "DELETE", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" +
-              "/virtualMachines/windowsmachine?api-version=2016-03-30");
+      assertSent(server, "DELETE", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute"
+            + "/virtualMachines/windowsmachine?api-version=2016-03-30");
    }
 
    public void testStart() throws Exception {
@@ -158,8 +190,8 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest {
 
       vmAPI.start("windowsmachine");
 
-      assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" +
-              "/virtualMachines/windowsmachine/start?api-version=2015-06-15");
+      assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute"
+            + "/virtualMachines/windowsmachine/start?api-version=2015-06-15");
    }
 
    public void testRestart() throws Exception {
@@ -169,8 +201,8 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest {
 
       vmAPI.restart("windowsmachine");
 
-      assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" +
-              "/virtualMachines/windowsmachine/restart?api-version=2015-06-15");
+      assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute"
+            + "/virtualMachines/windowsmachine/restart?api-version=2015-06-15");
    }
 
    public void testStop() throws Exception {
@@ -180,16 +212,16 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest {
 
       vmAPI.stop("windowsmachine");
 
-      assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" +
-              "/virtualMachines/windowsmachine/powerOff?api-version=2015-06-15");
+      assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute"
+            + "/virtualMachines/windowsmachine/powerOff?api-version=2015-06-15");
    }
 
    public void testGeneralize() throws Exception {
       server.enqueue(new MockResponse().setResponseCode(200));
       final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname");
       vmAPI.generalize("vm"); // IllegalStateException if failed
-      assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" +
-              "/virtualMachines/vm/generalize?api-version=2015-06-15");
+      assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute"
+            + "/virtualMachines/vm/generalize?api-version=2015-06-15");
    }
 
    public void testCapture() throws Exception {
@@ -198,8 +230,9 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest {
       final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname");
       URI uri = vmAPI.capture("vm", "prefix", "container");
       assertNotNull(uri);
-      assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" +
-              "/virtualMachines/vm/capture?api-version=2015-06-15", "{\"vhdPrefix\":\"prefix\",\"destinationContainerName\":\"container\"}");
+      assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute"
+            + "/virtualMachines/vm/capture?api-version=2015-06-15",
+            "{\"vhdPrefix\":\"prefix\",\"destinationContainerName\":\"container\"}");
    }
 
    public void testCapture404() throws Exception {
@@ -208,8 +241,9 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest {
       final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname");
       URI uri = vmAPI.capture("vm", "prefix", "container");
       assertNull(uri);
-      assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" +
-              "/virtualMachines/vm/capture?api-version=2015-06-15", "{\"vhdPrefix\":\"prefix\",\"destinationContainerName\":\"container\"}");
+      assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute"
+            + "/virtualMachines/vm/capture?api-version=2015-06-15",
+            "{\"vhdPrefix\":\"prefix\",\"destinationContainerName\":\"container\"}");
    }
 
    private VirtualMachineProperties getProperties() {
@@ -220,28 +254,36 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest {
       OSDisk osDisk = OSDisk.create("Windows", "windowsmachine", vhd, "ReadWrite", "FromImage", null);
       StorageProfile storageProfile = StorageProfile.create(imgRef, osDisk, dataDisks);
       OSProfile.WindowsConfiguration windowsConfig = OSProfile.WindowsConfiguration.create(false, null, null, true,
-              null);
+            null);
       OSProfile osProfile = OSProfile.create("windowsmachine", "azureuser", null, null, null, windowsConfig);
-      IdReference networkInterface =
-              IdReference.create("/subscriptions/SUBSCRIPTIONID" +
-                      "/resourceGroups/groupname/providers/Microsoft.Network/networkInterfaces/" +
-                      "windowsmachine167");
+      IdReference networkInterface = IdReference.create("/subscriptions/SUBSCRIPTIONID"
+            + "/resourceGroups/groupname/providers/Microsoft.Network/networkInterfaces/" + "windowsmachine167");
       List<IdReference> networkInterfaces = new ArrayList<IdReference>();
       networkInterfaces.add(networkInterface);
       NetworkProfile networkProfile = NetworkProfile.create(networkInterfaces);
       DiagnosticsProfile.BootDiagnostics bootDiagnostics = DiagnosticsProfile.BootDiagnostics.create(true,
-              "https://groupname2760.blob.core.windows.net/");
+            "https://groupname2760.blob.core.windows.net/");
       DiagnosticsProfile diagnosticsProfile = DiagnosticsProfile.create(bootDiagnostics);
       VirtualMachineProperties properties = VirtualMachineProperties.create("27ee085b-d707-xxxx-yyyy-2370e2eb1cc1",
-              null, null, hwProf, storageProfile, osProfile, networkProfile, diagnosticsProfile, VirtualMachineProperties.ProvisioningState.CREATING);
+            null, null, hwProf, storageProfile, osProfile, networkProfile, diagnosticsProfile,
+            VirtualMachineProperties.ProvisioningState.CREATING);
       return properties;
    }
 
    private VirtualMachine getVM() {
       VirtualMachineProperties properties = getProperties();
-      VirtualMachine machine = VirtualMachine.create("/subscriptions/SUBSCRIPTIONID/" + "" +
-                      "resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", "windowsmachine",
-              "Microsoft.Compute/virtualMachines", "westus", ImmutableMap.of("foo", "bar"), properties);
+      VirtualMachine machine = VirtualMachine.create("/subscriptions/SUBSCRIPTIONID/" + ""
+            + "resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", "windowsmachine",
+            "Microsoft.Compute/virtualMachines", "westus", ImmutableMap.of("foo", "bar"), properties,
+            Plan.create("thinkboxsoftware", "deadline-slave-7-2", "deadline7-2"));
+      return machine;
+   }
+   
+   private VirtualMachine getVM(Plan plan) {
+      VirtualMachineProperties properties = getProperties();
+      VirtualMachine machine = VirtualMachine.create("/subscriptions/SUBSCRIPTIONID/" + ""
+            + "resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", "windowsmachine",
+            "Microsoft.Compute/virtualMachines", "westus", ImmutableMap.of("foo", "bar"), properties, plan);
       return machine;
    }
 
@@ -255,23 +297,23 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest {
       } catch (Exception e) {
          e.printStackTrace();
       }
-      VirtualMachineInstance.VirtualMachineStatus vmStatus =
-              VirtualMachineInstance.VirtualMachineStatus.create("ProvisioningState/succeeded", "Info", "Provisioning succeeded",  date);
+      VirtualMachineInstance.VirtualMachineStatus vmStatus = VirtualMachineInstance.VirtualMachineStatus.create(
+            "ProvisioningState/succeeded", "Info", "Provisioning succeeded", date);
       statuses.add(vmStatus);
-      VirtualMachineInstance.VirtualMachineStatus vmStatus1 =
-              VirtualMachineInstance.VirtualMachineStatus.create("PowerState/running", "Info", "VM running",  null);
+      VirtualMachineInstance.VirtualMachineStatus vmStatus1 = VirtualMachineInstance.VirtualMachineStatus.create(
+            "PowerState/running", "Info", "VM running", null);
       statuses.add(vmStatus1);
 
-      VirtualMachineInstance machineInstance =
-              VirtualMachineInstance.create(null, null, ImmutableList.copyOf(statuses));
+      VirtualMachineInstance machineInstance = VirtualMachineInstance
+            .create(null, null, ImmutableList.copyOf(statuses));
       return machineInstance;
    }
 
    private List<VirtualMachine> getVMList() {
       VirtualMachineProperties properties = getProperties();
-      VirtualMachine machine = VirtualMachine.create("/subscriptions/SUBSCRIPTIONID/" + "" +
-                      "resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine",
-              "windowsmachine", "Microsoft.Compute/virtualMachines", "westus", null, properties);
+      VirtualMachine machine = VirtualMachine.create("/subscriptions/SUBSCRIPTIONID/" + ""
+            + "resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", "windowsmachine",
+            "Microsoft.Compute/virtualMachines", "westus", null, properties, null);
       List<VirtualMachine> list = new ArrayList<VirtualMachine>();
       list.add(machine);
       return list;

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f6e11340/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json b/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json
index 27464e8..2963100 100644
--- a/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json
+++ b/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json
@@ -46,5 +46,10 @@
   "location": "westus",
   "tags": {
     "foo": "bar"
+  },
+  "plan": {
+    "name": "deadline-slave-7-2",
+    "publisher": "thinkboxsoftware",
+    "product": "deadline7-2"
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f6e11340/azurecompute-arm/src/test/resources/virtualmachine.json
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/test/resources/virtualmachine.json b/azurecompute-arm/src/test/resources/virtualmachine.json
index 96a42be..874227d 100644
--- a/azurecompute-arm/src/test/resources/virtualmachine.json
+++ b/azurecompute-arm/src/test/resources/virtualmachine.json
@@ -46,5 +46,10 @@
   "location": "westus",
   "tags": {
     "foo": "bar"
+  },
+  "plan": {
+    "name": "deadline-slave-7-2",
+    "publisher": "thinkboxsoftware",
+    "product": "deadline7-2"
   }
 }