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:30 UTC

[09/50] [abbrv] jclouds git commit: JCLOUDS-1273/JCLOUDS-1226: Support multiple resource groups in ARM

http://git-wip-us.apache.org/repos/asf/jclouds/blob/83c0a3c7/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/CreateSecurityGroupIfNeeded.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/CreateSecurityGroupIfNeeded.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/CreateSecurityGroupIfNeeded.java
index 0ff96d8..bb5dc09 100644
--- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/CreateSecurityGroupIfNeeded.java
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/CreateSecurityGroupIfNeeded.java
@@ -28,7 +28,7 @@ import javax.inject.Named;
 import javax.inject.Singleton;
 
 import org.jclouds.azurecompute.arm.AzureComputeApi;
-import org.jclouds.azurecompute.arm.compute.domain.RegionAndIdAndIngressRules;
+import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndNameAndIngressRules;
 import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup;
 import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroupProperties;
 import org.jclouds.azurecompute.arm.domain.NetworkSecurityRule;
@@ -36,32 +36,27 @@ import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties;
 import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Access;
 import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Direction;
 import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Protocol;
-import org.jclouds.azurecompute.arm.domain.ResourceGroup;
 import org.jclouds.compute.reference.ComputeServiceConstants;
 import org.jclouds.logging.Logger;
 
 import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
 
 @Singleton
-public class CreateSecurityGroupIfNeeded extends CacheLoader<RegionAndIdAndIngressRules, String> {
+public class CreateSecurityGroupIfNeeded extends CacheLoader<ResourceGroupAndNameAndIngressRules, String> {
    @Resource
    @Named(ComputeServiceConstants.COMPUTE_LOGGER)
    protected Logger logger = Logger.NULL;
 
    private final AzureComputeApi api;
-   private final LoadingCache<String, ResourceGroup> resourceGroupMap;
 
    @Inject
-   CreateSecurityGroupIfNeeded(AzureComputeApi api, LoadingCache<String, ResourceGroup> resourceGroupMap) {
+   CreateSecurityGroupIfNeeded(AzureComputeApi api) {
       this.api = api;
-      this.resourceGroupMap = resourceGroupMap;
    }
 
    @Override
-   public String load(RegionAndIdAndIngressRules key) throws Exception {
-      ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(key.region());
-      return createSecurityGroup(key.region(), resourceGroup.name(), key.id(), key.inboundPorts());
+   public String load(ResourceGroupAndNameAndIngressRules key) throws Exception {
+      return createSecurityGroup(key.location(), key.resourceGroup(), key.name(), key.inboundPorts());
    }
 
    private String createSecurityGroup(String location, String resourceGroup, String name, int[] inboundPorts) {

http://git-wip-us.apache.org/repos/asf/jclouds/blob/83c0a3c7/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/DefaultResourceGroup.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/DefaultResourceGroup.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/DefaultResourceGroup.java
new file mode 100644
index 0000000..7caec25
--- /dev/null
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/DefaultResourceGroup.java
@@ -0,0 +1,62 @@
+/*
+ * 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.compute.loaders;
+
+import java.util.Map;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.azurecompute.arm.AzureComputeApi;
+import org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupName;
+import org.jclouds.azurecompute.arm.domain.ResourceGroup;
+import org.jclouds.azurecompute.arm.features.ResourceGroupApi;
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.logging.Logger;
+
+import com.google.common.cache.CacheLoader;
+import com.google.common.collect.ImmutableMap;
+
+@Singleton
+public class DefaultResourceGroup extends CacheLoader<String, ResourceGroup> {
+   @Resource
+   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+   protected Logger logger = Logger.NULL;
+
+   private final ResourceGroupApi api;
+   private final LocationToResourceGroupName locationToResourceGroupName;
+
+   @Inject
+   DefaultResourceGroup(AzureComputeApi api, LocationToResourceGroupName locationToResourceGroupName) {
+      this.api = api.getResourceGroupApi();
+      this.locationToResourceGroupName = locationToResourceGroupName;
+   }
+
+   @Override
+   public ResourceGroup load(String locationId) throws Exception {
+      String azureGroupName = locationToResourceGroupName.apply(locationId);
+      ResourceGroup resourceGroup = api.get(azureGroupName);
+      if (resourceGroup == null) {
+         logger.debug(">> creating resource group %s", azureGroupName);
+         final Map<String, String> tags = ImmutableMap.of("description", "jclouds default resource group");
+         resourceGroup = api.create(azureGroupName, locationId, tags);
+      }
+      return resourceGroup;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/83c0a3c7/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/ResourceGroupForLocation.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/ResourceGroupForLocation.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/ResourceGroupForLocation.java
deleted file mode 100644
index ddbbb26..0000000
--- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/ResourceGroupForLocation.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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.compute.loaders;
-
-import java.util.Map;
-
-import javax.annotation.Resource;
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.jclouds.azurecompute.arm.AzureComputeApi;
-import org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupName;
-import org.jclouds.azurecompute.arm.domain.ResourceGroup;
-import org.jclouds.azurecompute.arm.features.ResourceGroupApi;
-import org.jclouds.compute.reference.ComputeServiceConstants;
-import org.jclouds.logging.Logger;
-
-import com.google.common.cache.CacheLoader;
-import com.google.common.collect.ImmutableMap;
-
-@Singleton
-public class ResourceGroupForLocation extends CacheLoader<String, ResourceGroup> {
-   @Resource
-   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
-   protected Logger logger = Logger.NULL;
-
-   private final ResourceGroupApi api;
-   private final LocationToResourceGroupName locationToResourceGroupName;
-
-   @Inject
-   ResourceGroupForLocation(AzureComputeApi api, LocationToResourceGroupName locationToResourceGroupName) {
-      this.api = api.getResourceGroupApi();
-      this.locationToResourceGroupName = locationToResourceGroupName;
-   }
-
-   @Override
-   public ResourceGroup load(String locationId) throws Exception {
-      String azureGroupName = locationToResourceGroupName.apply(locationId);
-      ResourceGroup resourceGroup = api.get(azureGroupName);
-      if (resourceGroup == null) {
-         logger.debug(">> creating resource group %s", azureGroupName);
-         final Map<String, String> tags = ImmutableMap.of("description", "jclouds managed VMs");
-         resourceGroup = api.create(azureGroupName, locationId, tags);
-      }
-      return resourceGroup;
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/83c0a3c7/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 5566ecf..d211421 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
@@ -34,10 +34,10 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable {
 
    private String virtualNetworkName;
    private String subnetId;
-   private String blob;
    private AvailabilitySet availabilitySet;
    private String availabilitySetName;
    private List<DataDisk> dataDisks = ImmutableList.of();
+   private String resourceGroup;
 
    /**
     * Sets the virtual network name
@@ -54,14 +54,6 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable {
       this.subnetId = subnetId;
       return this;
    }
-
-   /**
-    * Sets the blob name
-    */
-   public  AzureTemplateOptions blob(String blob) {
-      this.blob = blob;
-      return this;
-   }
    
    /**
     * Sets the availability set where the nodes will be configured. If it does
@@ -80,6 +72,14 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable {
       this.availabilitySetName = availabilitySetName;
       return this;
    }
+   
+   /**
+    * The resource group where the new resources will be created.
+    */
+   public AzureTemplateOptions resourceGroup(String resourceGroup) {
+      this.resourceGroup = resourceGroup;
+      return this;
+   }
 
    public AzureTemplateOptions dataDisks(Iterable<DataDisk> dataDisks) {
       for (DataDisk dataDisk : checkNotNull(dataDisks, "dataDisks"))
@@ -94,12 +94,10 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable {
    
    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;
-   }
+   public List<DataDisk> getDataDisks() { return dataDisks; }
+   public String getResourceGroup() { return resourceGroup; }
 
    @Override
    public AzureTemplateOptions clone() {
@@ -115,10 +113,10 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable {
          AzureTemplateOptions eTo = AzureTemplateOptions.class.cast(to);
          eTo.virtualNetworkName(virtualNetworkName);
          eTo.subnetId(subnetId);
-         eTo.blob(blob);
          eTo.availabilitySet(availabilitySet);
          eTo.availabilitySet(availabilitySetName);
          eTo.dataDisks(dataDisks);
+         eTo.resourceGroup(resourceGroup);
       }
    }
 
@@ -129,28 +127,19 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable {
       if (!super.equals(o)) return false;
 
       AzureTemplateOptions that = (AzureTemplateOptions) o;
-
-      if (virtualNetworkName != null ? !virtualNetworkName.equals(that.virtualNetworkName) : that.virtualNetworkName != null)
-         return false;
-      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;
-      if (availabilitySetName != null ? !availabilitySetName.equals(that.availabilitySetName) : that.availabilitySetName != null)
-         return false;
-      return dataDisks != null ? dataDisks.equals(that.dataDisks) : that.dataDisks == null;
+      
+      return Objects.equal(virtualNetworkName, that.virtualNetworkName) &&
+            Objects.equal(subnetId, that.subnetId) &&
+            Objects.equal(availabilitySet, that.availabilitySet) &&
+            Objects.equal(availabilitySetName, that.availabilitySetName) &&
+            Objects.equal(dataDisks, that.dataDisks) &&
+            Objects.equal(resourceGroup, that.resourceGroup);
    }
 
    @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;
+      return Objects.hashCode(virtualNetworkName, subnetId, availabilitySet, availabilitySetName, dataDisks,
+            resourceGroup);
    }
 
    @Override
@@ -160,14 +149,14 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable {
          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);
+      if (resourceGroup != null)
+         toString.add("resourceGroup", resourceGroup);
       return toString;
    }
 
@@ -188,14 +177,6 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable {
          AzureTemplateOptions options = new AzureTemplateOptions();
          return options.subnetId(subnetId);
       }
-
-      /**
-       * @see AzureTemplateOptions#blob(String)
-       */
-      public static AzureTemplateOptions blob(String blob) {
-         AzureTemplateOptions options = new AzureTemplateOptions();
-         return options.blob(blob);
-      }
       
       /**
        * @see AzureTemplateOptions#availabilitySet(AvailabilitySet)
@@ -214,16 +195,27 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable {
       }
 
       /**
-       * @see AzureTemplateOptions#dataDisks
+       * @see AzureTemplateOptions#dataDisks(DataDisk...)
        */
       public static AzureTemplateOptions dataDisks(DataDisk... dataDisks) {
          AzureTemplateOptions options = new AzureTemplateOptions();
          return options.dataDisks(dataDisks);
       }
 
+      /**
+       * @see AzureTemplateOptions#dataDisks(Iterable)
+       */
       public static AzureTemplateOptions dataDisks(Iterable<DataDisk> dataDisks) {
          AzureTemplateOptions options = new AzureTemplateOptions();
          return options.dataDisks(dataDisks);
       }
+      
+      /**
+       * @see AzureTemplateOptions#resourceGroup(String)
+       */
+      public static AzureTemplateOptions resourceGroup(String resourceGroup) {
+         AzureTemplateOptions options = new AzureTemplateOptions();
+         return options.resourceGroup(resourceGroup);
+      }
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/83c0a3c7/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java
index fb635aa..79f2cd0 100644
--- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java
@@ -30,13 +30,12 @@ import javax.inject.Named;
 import javax.inject.Singleton;
 
 import org.jclouds.azurecompute.arm.AzureComputeApi;
+import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName;
 import org.jclouds.azurecompute.arm.domain.AvailabilitySet;
 import org.jclouds.azurecompute.arm.domain.IdReference;
 import org.jclouds.azurecompute.arm.domain.IpConfiguration;
 import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard;
 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.VirtualMachine;
 import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi;
 import org.jclouds.compute.functions.GroupNamingConvention;
@@ -45,10 +44,6 @@ import org.jclouds.logging.Logger;
 
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
-import com.google.common.base.Splitter;
-import com.google.common.cache.LoadingCache;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
 
 @Singleton
 public class CleanupResources {
@@ -59,52 +54,55 @@ public class CleanupResources {
 
    private final AzureComputeApi api;
    private final Predicate<URI> resourceDeleted;
-   private final LoadingCache<String, ResourceGroup> resourceGroupMap;
    private final GroupNamingConvention.Factory namingConvention;
 
    @Inject
    CleanupResources(AzureComputeApi azureComputeApi, @Named(TIMEOUT_RESOURCE_DELETED) Predicate<URI> resourceDeleted,
-         LoadingCache<String, ResourceGroup> resourceGroupMap, GroupNamingConvention.Factory namingConvention) {
+         GroupNamingConvention.Factory namingConvention) {
       this.api = azureComputeApi;
       this.resourceDeleted = resourceDeleted;
-      this.resourceGroupMap = resourceGroupMap;
       this.namingConvention = namingConvention;
    }
 
    public boolean cleanupNode(final String id) {
-      RegionAndId regionAndId = RegionAndId.fromSlashEncoded(id);
-      ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(regionAndId.region());
-      String resourceGroupName = resourceGroup.name();
+      ResourceGroupAndName resourceGroupAndName = ResourceGroupAndName.fromSlashEncoded(id);
+      String resourceGroupName = resourceGroupAndName.resourceGroup();
 
-      VirtualMachine virtualMachine = api.getVirtualMachineApi(resourceGroupName).get(regionAndId.id());
+      VirtualMachine virtualMachine = api.getVirtualMachineApi(resourceGroupName).get(resourceGroupAndName.name());
       if (virtualMachine == null) {
          return true;
       }
 
-      logger.debug(">> destroying %s ...", regionAndId.slashEncode());
+      logger.debug(">> destroying %s ...", id);
       boolean vmDeleted = deleteVirtualMachine(resourceGroupName, virtualMachine);
 
       // We don't delete the network here, as it is global to the resource
       // group. It will be deleted when the resource group is deleted
 
-      cleanupVirtualMachineNICs(resourceGroupName, virtualMachine);
-      cleanupAvailabilitySetIfOrphaned(resourceGroupName, virtualMachine);
+      cleanupVirtualMachineNICs(virtualMachine);
+      cleanupAvailabilitySetIfOrphaned(virtualMachine);
 
       return vmDeleted;
    }
 
-   public void cleanupVirtualMachineNICs(String group, VirtualMachine virtualMachine) {
-      for (String nicName : getNetworkCardInterfaceNames(virtualMachine)) {
-         NetworkInterfaceCard nic = api.getNetworkInterfaceCardApi(group).get(nicName);
-         Iterable<String> publicIps = getPublicIps(group, nic);
+   public void cleanupVirtualMachineNICs(VirtualMachine virtualMachine) {
+      for (IdReference nicRef : virtualMachine.properties().networkProfile().networkInterfaces()) {
+         String nicResourceGroup = nicRef.resourceGroup();
+         String nicName = nicRef.name();
+         NetworkInterfaceCard nic = api.getNetworkInterfaceCardApi(nicRef.resourceGroup()).get(nicName);
+         
+         Iterable<IdReference> publicIps = getPublicIps(nic);
 
          logger.debug(">> destroying nic %s...", nicName);
-         URI nicDeletionURI = api.getNetworkInterfaceCardApi(group).delete(nicName);
+         URI nicDeletionURI = api.getNetworkInterfaceCardApi(nicResourceGroup).delete(nicName);
          resourceDeleted.apply(nicDeletionURI);
 
-         for (String publicIp : publicIps) {
-            logger.debug(">> deleting public ip nic %s...", publicIp);
-            api.getPublicIPAddressApi(group).delete(publicIp);
+         for (IdReference publicIp : publicIps) {
+            String publicIpResourceGroup = publicIp.resourceGroup();
+            String publicIpName = publicIp.name();
+            
+            logger.debug(">> deleting public ip nic %s...", publicIpName);
+            api.getPublicIPAddressApi(publicIpResourceGroup).delete(publicIpName);
          }
       }
    }
@@ -135,12 +133,13 @@ public class CleanupResources {
       return deleted;
    }
 
-   public boolean cleanupAvailabilitySetIfOrphaned(String resourceGroup, VirtualMachine virtualMachine) {
+   public boolean cleanupAvailabilitySetIfOrphaned(VirtualMachine virtualMachine) {
       boolean deleted = false;
       IdReference availabilitySetRef = virtualMachine.properties().availabilitySet();
 
       if (availabilitySetRef != null) {
-         String name = Iterables.getLast(Splitter.on("/").split(availabilitySetRef.id()));
+         String name = availabilitySetRef.name();
+         String resourceGroup = availabilitySetRef.resourceGroup();
          AvailabilitySet availabilitySet = api.getAvailabilitySetApi(resourceGroup).get(name);
 
          if (isOrphanedJcloudsAvailabilitySet(availabilitySet)) {
@@ -162,19 +161,13 @@ public class CleanupResources {
       return deleted;
    }
 
-   private Iterable<String> getPublicIps(String group, NetworkInterfaceCard nic) {
-      return transform(
-            filter(transform(nic.properties().ipConfigurations(), new Function<IpConfiguration, IdReference>() {
-               @Override
-               public IdReference apply(IpConfiguration input) {
-                  return input.properties().publicIPAddress();
-               }
-            }), notNull()), new Function<IdReference, String>() {
-               @Override
-               public String apply(IdReference input) {
-                  return Iterables.getLast(Splitter.on("/").split(input.id()));
-               }
-            });
+   private Iterable<IdReference> getPublicIps(NetworkInterfaceCard nic) {
+      return filter(transform(nic.properties().ipConfigurations(), new Function<IpConfiguration, IdReference>() {
+         @Override
+         public IdReference apply(IpConfiguration input) {
+            return input.properties().publicIPAddress();
+         }
+      }), notNull());
    }
 
    private static boolean isOrphanedJcloudsAvailabilitySet(AvailabilitySet availabilitySet) {
@@ -187,14 +180,6 @@ public class CleanupResources {
                   .virtualMachines().isEmpty());
    }
 
-   private List<String> getNetworkCardInterfaceNames(VirtualMachine virtualMachine) {
-      List<String> nics = Lists.newArrayList();
-      for (IdReference idReference : virtualMachine.properties().networkProfile().networkInterfaces()) {
-         nics.add(Iterables.getLast(Splitter.on("/").split(idReference.id())));
-      }
-      return nics;
-   }
-
    private boolean deleteVirtualMachine(String group, VirtualMachine virtualMachine) {
       return resourceDeleted.apply(api.getVirtualMachineApi(group).delete(virtualMachine.name()));
    }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/83c0a3c7/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
deleted file mode 100644
index 5f6d88f..0000000
--- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourceGroupThenCreateNodes.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * 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.compute.strategy;
-
-import java.util.Arrays;
-import java.util.Map;
-import java.util.Set;
-
-import javax.annotation.Resource;
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.jclouds.Constants;
-import org.jclouds.azurecompute.arm.AzureComputeApi;
-import org.jclouds.azurecompute.arm.compute.domain.RegionAndIdAndIngressRules;
-import org.jclouds.azurecompute.arm.compute.functions.TemplateToAvailabilitySet;
-import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions;
-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.Subnet;
-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.NodeMetadata;
-import org.jclouds.compute.domain.Template;
-import org.jclouds.compute.functions.GroupNamingConvention;
-import org.jclouds.compute.options.TemplateOptions;
-import org.jclouds.compute.reference.ComputeServiceConstants;
-import org.jclouds.compute.strategy.CreateNodeWithGroupEncodedIntoName;
-import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
-import org.jclouds.compute.strategy.ListNodesStrategy;
-import org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet;
-import org.jclouds.domain.Location;
-import org.jclouds.logging.Logger;
-
-import com.google.common.base.Optional;
-import com.google.common.cache.LoadingCache;
-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 {
-
-   @Resource
-   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
-   protected Logger logger = Logger.NULL;
-
-   private final AzureComputeApi api;
-   private final LoadingCache<RegionAndIdAndIngressRules, String> securityGroupMap;
-   private final LoadingCache<String, ResourceGroup> resourceGroupMap;
-   private final String defaultVnetAddressPrefix;
-   private final String defaultSubnetAddressPrefix;
-   private final TemplateToAvailabilitySet templateToAvailabilitySet;
-
-   @Inject
-   protected CreateResourceGroupThenCreateNodes(
-         CreateNodeWithGroupEncodedIntoName addNodeWithGroupStrategy,
-         ListNodesStrategy listNodesStrategy,
-         GroupNamingConvention.Factory namingConvention,
-         @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor,
-         CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory,
-         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, 
-         TemplateToAvailabilitySet templateToAvailabilitySet) {
-      super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor,
-            customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory);
-      this.api = checkNotNull(api, "api cannot be null");
-      checkNotNull(userExecutor, "userExecutor cannot be null");
-      this.securityGroupMap = securityGroupMap;
-      this.resourceGroupMap = resourceGroupMap;
-      this.defaultVnetAddressPrefix = defaultVnetAddressPrefix;
-      this.defaultSubnetAddressPrefix = defaultSubnetAddressPrefix;
-      this.templateToAvailabilitySet = templateToAvailabilitySet;
-   }
-
-   @Override
-   public Map<?, ListenableFuture<Void>> execute(String group, int count, Template template,
-         Set<NodeMetadata> goodNodes, Map<NodeMetadata, Exception> badNodes,
-         Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
-
-      AzureTemplateOptions options = template.getOptions().as(AzureTemplateOptions.class);
-
-      // If there is a script to be run on the node and public key
-      // authentication has been configured, warn users if the private key
-      // is not present
-      if (hasRunScriptWithKeyAuthAndNoPrivateKey(template)) {
-         logger.warn(">> a runScript was configured but no SSH key has been provided. "
-               + "Authentication will delegate to the ssh-agent");
-      }
-
-      // This sill create the resource group if it does not exist
-      String location = template.getLocation().getId();
-      ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(location);
-      String azureGroupName = resourceGroup.name();
-
-      getOrCreateVirtualNetworkWithSubnet(location, options, azureGroupName);
-      configureSecurityGroupForOptions(group, azureGroupName, template.getLocation(), options);
-      configureAvailabilitySetForTemplate(template);
-
-      return super.execute(group, count, template, goodNodes, badNodes, customizationResponses);
-   }
-
-   protected synchronized void getOrCreateVirtualNetworkWithSubnet(final String location, AzureTemplateOptions options,
-         final String azureGroupName) {
-      String virtualNetworkName = Optional.fromNullable(options.getVirtualNetworkName()).or(
-            azureGroupName + "virtualnetwork");
-      String subnetName = azureGroupName + "subnet";
-
-      // Subnets belong to a virtual network so that needs to be created first
-      VirtualNetworkApi vnApi = api.getVirtualNetworkApi(azureGroupName);
-      VirtualNetwork vn = vnApi.get(virtualNetworkName);
-
-      if (vn == null) {
-         Subnet subnet = Subnet.create(subnetName, null, null,
-               Subnet.SubnetProperties.builder().addressPrefix(defaultSubnetAddressPrefix).build());
-
-         VirtualNetwork.VirtualNetworkProperties virtualNetworkProperties = VirtualNetwork.VirtualNetworkProperties
-               .builder().addressSpace(VirtualNetwork.AddressSpace.create(Arrays.asList(defaultVnetAddressPrefix)))
-               .subnets(Arrays.asList(subnet)).build();
-
-         vn = vnApi.createOrUpdate(virtualNetworkName, location, virtualNetworkProperties);
-      }
-
-      SubnetApi subnetApi = api.getSubnetApi(azureGroupName, virtualNetworkName);
-      Subnet subnet = subnetApi.get(subnetName);
-
-      options.virtualNetworkName(virtualNetworkName);
-      options.subnetId(subnet.id());
-   }
-
-   private static boolean hasRunScriptWithKeyAuthAndNoPrivateKey(Template template) {
-      return template.getOptions().getRunScript() != null && template.getOptions().getPublicKey() != null
-            && !template.getOptions().hasLoginPrivateKeyOption();
-   }
-
-   private void configureSecurityGroupForOptions(String group, String resourceGroup, Location location,
-         TemplateOptions options) {
-
-      checkArgument(options.getGroups().size() <= 1,
-            "Only one security group can be configured for each network interface");
-
-      if (!options.getGroups().isEmpty()) {
-         String groupName = getOnlyElement(options.getGroups());
-         String groupNameWithourRegion = groupName.indexOf('/') == -1 ? groupName : RegionAndId.fromSlashEncoded(
-               groupName).id();
-         NetworkSecurityGroup securityGroup = api.getNetworkSecurityGroupApi(resourceGroup).get(groupNameWithourRegion);
-         checkArgument(securityGroup != null, "Security group %s was not found", groupName);
-         options.securityGroups(securityGroup.id());
-      } else if (options.getInboundPorts().length > 0) {
-         String name = namingConvention.create().sharedNameForGroup(group);
-         RegionAndIdAndIngressRules regionAndIdAndIngressRules = RegionAndIdAndIngressRules.create(location.getId(),
-               name, options.getInboundPorts());
-         // this will create if not yet exists.
-         String securityGroupId = securityGroupMap.getUnchecked(regionAndIdAndIngressRules);
-         options.securityGroups(securityGroupId);
-      }
-   }
-   
-   private void configureAvailabilitySetForTemplate(Template template) {
-      AvailabilitySet availabilitySet = templateToAvailabilitySet.apply(template);
-      if (availabilitySet != null) {
-         logger.debug(">> configuring nodes in availability set [%s]", availabilitySet.name());
-         template.getOptions().as(AzureTemplateOptions.class).availabilitySet(availabilitySet);
-      }
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/83c0a3c7/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java
new file mode 100644
index 0000000..c3bdbdd
--- /dev/null
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java
@@ -0,0 +1,199 @@
+/*
+ * 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.compute.strategy;
+
+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;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.Constants;
+import org.jclouds.azurecompute.arm.AzureComputeApi;
+import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName;
+import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndNameAndIngressRules;
+import org.jclouds.azurecompute.arm.compute.functions.TemplateToAvailabilitySet;
+import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions;
+import org.jclouds.azurecompute.arm.domain.AvailabilitySet;
+import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup;
+import org.jclouds.azurecompute.arm.domain.ResourceGroup;
+import org.jclouds.azurecompute.arm.domain.Subnet;
+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.NodeMetadata;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.functions.GroupNamingConvention;
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.compute.strategy.CreateNodeWithGroupEncodedIntoName;
+import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
+import org.jclouds.compute.strategy.ListNodesStrategy;
+import org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet;
+import org.jclouds.domain.Location;
+import org.jclouds.logging.Logger;
+
+import com.google.common.base.Optional;
+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;
+
+@Singleton
+public class CreateResourcesThenCreateNodes extends CreateNodesWithGroupEncodedIntoNameThenAddToSet {
+
+   @Resource
+   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+   protected Logger logger = Logger.NULL;
+
+   private final AzureComputeApi api;
+   private final LoadingCache<ResourceGroupAndNameAndIngressRules, String> securityGroupMap;
+   private final String defaultVnetAddressPrefix;
+   private final String defaultSubnetAddressPrefix;
+   private final TemplateToAvailabilitySet templateToAvailabilitySet;
+
+   @Inject
+   protected CreateResourcesThenCreateNodes(
+         CreateNodeWithGroupEncodedIntoName addNodeWithGroupStrategy,
+         ListNodesStrategy listNodesStrategy,
+         GroupNamingConvention.Factory namingConvention,
+         @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor,
+         CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory,
+         AzureComputeApi api, @Named(DEFAULT_VNET_ADDRESS_SPACE_PREFIX) String defaultVnetAddressPrefix,
+         @Named(DEFAULT_SUBNET_ADDRESS_PREFIX) String defaultSubnetAddressPrefix,
+         LoadingCache<ResourceGroupAndNameAndIngressRules, String> securityGroupMap,
+         TemplateToAvailabilitySet templateToAvailabilitySet) {
+      super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor,
+            customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory);
+      this.api = checkNotNull(api, "api cannot be null");
+      checkNotNull(userExecutor, "userExecutor cannot be null");
+      this.securityGroupMap = securityGroupMap;
+      this.defaultVnetAddressPrefix = defaultVnetAddressPrefix;
+      this.defaultSubnetAddressPrefix = defaultSubnetAddressPrefix;
+      this.templateToAvailabilitySet = templateToAvailabilitySet;
+   }
+
+   @Override
+   public Map<?, ListenableFuture<Void>> execute(String group, int count, Template template,
+         Set<NodeMetadata> goodNodes, Map<NodeMetadata, Exception> badNodes,
+         Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
+
+      AzureTemplateOptions options = template.getOptions().as(AzureTemplateOptions.class);
+
+      // If there is a script to be run on the node and public key
+      // authentication has been configured, warn users if the private key
+      // is not present
+      if (hasRunScriptWithKeyAuthAndNoPrivateKey(template)) {
+         logger.warn(">> a runScript was configured but no SSH key has been provided. "
+               + "Authentication will delegate to the ssh-agent");
+      }
+
+      // This sill create the resource group if it does not exist
+      String location = template.getLocation().getId();
+
+      createResourceGroupIfNeeded(group, location, options);
+      getOrCreateVirtualNetworkWithSubnet(location, options);
+      configureSecurityGroupForOptions(group, template.getLocation(), options);
+      configureAvailabilitySetForTemplate(template);
+
+      return super.execute(group, count, template, goodNodes, badNodes, customizationResponses);
+   }
+
+   protected synchronized void getOrCreateVirtualNetworkWithSubnet(final String location, AzureTemplateOptions options) {
+      String virtualNetworkName = Optional.fromNullable(options.getVirtualNetworkName()).or(
+            options.getResourceGroup() + "virtualnetwork");
+      String subnetName = options.getResourceGroup() + "subnet";
+
+      // Subnets belong to a virtual network so that needs to be created first
+      VirtualNetworkApi vnApi = api.getVirtualNetworkApi(options.getResourceGroup());
+      VirtualNetwork vn = vnApi.get(virtualNetworkName);
+
+      if (vn == null) {
+         Subnet subnet = Subnet.create(subnetName, null, null,
+               Subnet.SubnetProperties.builder().addressPrefix(defaultSubnetAddressPrefix).build());
+
+         VirtualNetwork.VirtualNetworkProperties virtualNetworkProperties = VirtualNetwork.VirtualNetworkProperties
+               .builder().addressSpace(VirtualNetwork.AddressSpace.create(Arrays.asList(defaultVnetAddressPrefix)))
+               .subnets(Arrays.asList(subnet)).build();
+
+         vn = vnApi.createOrUpdate(virtualNetworkName, location, virtualNetworkProperties);
+      }
+
+      SubnetApi subnetApi = api.getSubnetApi(options.getResourceGroup(), virtualNetworkName);
+      Subnet subnet = subnetApi.get(subnetName);
+
+      options.virtualNetworkName(virtualNetworkName);
+      options.subnetId(subnet.id());
+   }
+
+   private static boolean hasRunScriptWithKeyAuthAndNoPrivateKey(Template template) {
+      return template.getOptions().getRunScript() != null && template.getOptions().getPublicKey() != null
+            && !template.getOptions().hasLoginPrivateKeyOption();
+   }
+
+   private void configureSecurityGroupForOptions(String group, Location location, AzureTemplateOptions options) {
+
+      checkArgument(options.getGroups().size() <= 1,
+            "Only one security group can be configured for each network interface");
+
+      if (!options.getGroups().isEmpty()) {
+         ResourceGroupAndName securityGroupId = ResourceGroupAndName.fromSlashEncoded(getOnlyElement(options.getGroups()));
+         NetworkSecurityGroup securityGroup = api.getNetworkSecurityGroupApi(securityGroupId.resourceGroup()).get(
+               securityGroupId.name());
+         checkArgument(securityGroup != null, "Security group %s was not found", securityGroupId.slashEncode());
+         options.securityGroups(securityGroup.id());
+      } else if (options.getInboundPorts().length > 0) {
+         String name = namingConvention.create().sharedNameForGroup(group);
+         ResourceGroupAndNameAndIngressRules regionAndIdAndIngressRules = ResourceGroupAndNameAndIngressRules.create(
+               options.getResourceGroup(), location.getId(), name, options.getInboundPorts());
+         // this will create if not yet exists.
+         String securityGroupId = securityGroupMap.getUnchecked(regionAndIdAndIngressRules);
+         options.securityGroups(securityGroupId);
+      }
+   }
+   
+   private void configureAvailabilitySetForTemplate(Template template) {
+      AvailabilitySet availabilitySet = templateToAvailabilitySet.apply(template);
+      if (availabilitySet != null) {
+         logger.debug(">> configuring nodes in availability set [%s]", availabilitySet.name());
+         template.getOptions().as(AzureTemplateOptions.class).availabilitySet(availabilitySet);
+      }
+   }
+   
+   private void createResourceGroupIfNeeded(String group, String location, AzureTemplateOptions options) {
+      if (options.getResourceGroup() == null) {
+         options.resourceGroup(group);
+      }
+      logger.debug(">> using resource group [%s]", options.getResourceGroup());
+      ResourceGroup rg = api.getResourceGroupApi().get(options.getResourceGroup());
+      if (rg == null) {
+         logger.debug(">> resource group [%s] does not exist. Creating!", options.getResourceGroup());
+         api.getResourceGroupApi().create(options.getResourceGroup(), location,
+               ImmutableMap.of("description", "jclouds default resource group"));
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/83c0a3c7/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IdReference.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IdReference.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IdReference.java
index 1854897..f73e3e4 100644
--- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IdReference.java
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IdReference.java
@@ -16,19 +16,56 @@
  */
 package org.jclouds.azurecompute.arm.domain;
 
-import com.google.auto.value.AutoValue;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
 import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.json.SerializedNames;
 
+import com.google.auto.value.AutoValue;
+
 // Simple helper class to serialize / deserialize id reference.
 
 @AutoValue
 public abstract class IdReference {
+   
+   private static final Pattern RESOURCE_GROUP_PATTERN = Pattern.compile("^.*/resourceGroups/([^/]+)(/.*)?$");
+   
    @Nullable
    public abstract String id();
+   
+   @Nullable
+   public String resourceGroup() {
+      return extractResourceGroup(id());
+   }
+   
+   @Nullable
+   public String name() {
+      return extractName(id());
+   }
 
    @SerializedNames({"id"})
    public static IdReference create(final String id) {
       return new AutoValue_IdReference(id);
    }
+   
+   /**
+    * Extracts the name from the given URI.
+    */
+   public static String extractName(String uri) {
+      if (uri == null)
+         return null;
+      String noSlashAtEnd = uri.replaceAll("/+$", "");
+      return noSlashAtEnd.substring(noSlashAtEnd.lastIndexOf('/') + 1);
+   }
+   
+   /**
+    * Extracts the resource group name from the given URI.
+    */
+   public static String extractResourceGroup(String uri) {
+      if (uri == null)
+         return null;
+      Matcher m = RESOURCE_GROUP_PATTERN.matcher(uri);
+      return m.matches() ? m.group(1) : null;
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/83c0a3c7/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/RegionAndId.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/RegionAndId.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/RegionAndId.java
deleted file mode 100644
index 4105ee3..0000000
--- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/RegionAndId.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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 static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.auto.value.AutoValue;
-import com.google.common.base.Splitter;
-import com.google.common.collect.Iterables;
-
-@AutoValue
-public abstract class RegionAndId {
-
-   public abstract String region();
-   public abstract String id();
-   
-   protected RegionAndId() {
-      
-   }
-   
-   public static RegionAndId fromSlashEncoded(String id) {
-      Iterable<String> parts = Splitter.on('/').split(checkNotNull(id, "id"));
-      checkArgument(Iterables.size(parts) == 2, "id must be in format regionId/id");
-      return new AutoValue_RegionAndId(Iterables.get(parts, 0), Iterables.get(parts, 1));
-   }
-
-   public static RegionAndId fromRegionAndId(String region, String id) {
-      return new AutoValue_RegionAndId(region, id);
-   }
-
-   public String slashEncode() {
-      return region() + "/" + id();
-   }
-   
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/83c0a3c7/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMHardware.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMHardware.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMHardware.java
index f0aa77e..e771903 100644
--- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMHardware.java
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMHardware.java
@@ -62,14 +62,9 @@ public abstract class VMHardware {
     */
    public abstract String location();
 
-   /**
-    * Specifies if this HW is globally available
-    */
-   public abstract boolean globallyAvailable();
-
-   @SerializedNames({ "name", "numberOfCores", "osDiskSizeInMB", "resourceDiskSizeInMB", "memoryInMB", "maxDataDiskCount", "location", "globallyAvailable"})
-   public static VMHardware create(String name, Integer numberOfCores, Integer osDiskSizeInMB, Integer resourceDiskSizeInMB, Integer memoryInMB, Integer maxDataDiskCount, String location, boolean globallyAvailable) {
+   @SerializedNames({ "name", "numberOfCores", "osDiskSizeInMB", "resourceDiskSizeInMB", "memoryInMB", "maxDataDiskCount", "location"})
+   public static VMHardware create(String name, Integer numberOfCores, Integer osDiskSizeInMB, Integer resourceDiskSizeInMB, Integer memoryInMB, Integer maxDataDiskCount, String location) {
 
-      return new AutoValue_VMHardware(name, numberOfCores, osDiskSizeInMB, resourceDiskSizeInMB, memoryInMB, maxDataDiskCount, location, globallyAvailable);
+      return new AutoValue_VMHardware(name, numberOfCores, osDiskSizeInMB, resourceDiskSizeInMB, memoryInMB, maxDataDiskCount, location);
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/83c0a3c7/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java
index a01ed23..91ca818 100644
--- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java
@@ -98,6 +98,13 @@ public abstract class VMImage {
     */
    @Nullable
    public abstract String customImageId();
+   
+   /**
+    * The resource group for the image in case of custom images.
+    * @return
+    */
+   @Nullable
+   public abstract String resourceGroup();
 
    /**
     * Extended version properties.
@@ -127,6 +134,7 @@ public abstract class VMImage {
    public abstract static class Builder {
 
       public abstract Builder customImageId(String id);
+      public abstract Builder resourceGroup(String resourceGroup);
       public abstract Builder publisher(String published);
       public abstract Builder offer(String offer);
       public abstract Builder sku(String sku);

http://git-wip-us.apache.org/repos/asf/jclouds/blob/83c0a3c7/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/JobApi.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/JobApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/JobApi.java
index 5a01e90..a854fed 100644
--- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/JobApi.java
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/JobApi.java
@@ -15,6 +15,7 @@
  * limitations under the License.
  */
 package org.jclouds.azurecompute.arm.features;
+
 import java.io.Closeable;
 import java.net.URI;
 import java.util.List;
@@ -37,7 +38,6 @@ import org.jclouds.rest.annotations.SelectJson;
 /**
  * The Azure Resource Manager API checks for job status and progress.
  */
-
 @RequestFilters(OAuthFilter.class)
 @Consumes(MediaType.APPLICATION_JSON)
 public interface JobApi extends Closeable {

http://git-wip-us.apache.org/repos/asf/jclouds/blob/83c0a3c7/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
index a5944ec..238832e 100644
--- 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
@@ -21,7 +21,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
 public class VMImages {
 
    public static boolean isCustom(String imageId) {
-      return checkNotNull(imageId, "id").split("/").length == 2;
+      return checkNotNull(imageId, "id").split("/").length == 3;
    }
   
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/83c0a3c7/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceLiveTest.java
index 7c5c97f..46f4ed4 100644
--- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceLiveTest.java
+++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceLiveTest.java
@@ -16,8 +16,8 @@
  */
 package org.jclouds.azurecompute.arm.compute;
 
+import static org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions.Builder.resourceGroup;
 import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED;
-import static org.jclouds.compute.options.TemplateOptions.Builder.authorizePublicKey;
 import static org.testng.Assert.assertTrue;
 
 import java.net.URI;
@@ -25,7 +25,6 @@ import java.util.Properties;
 
 import org.jclouds.azurecompute.arm.AzureComputeApi;
 import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata;
-import org.jclouds.azurecompute.arm.domain.ResourceGroup;
 import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils;
 import org.jclouds.compute.domain.Template;
 import org.jclouds.compute.domain.TemplateBuilder;
@@ -42,7 +41,6 @@ import org.testng.annotations.AfterClass;
 import org.testng.annotations.Test;
 
 import com.google.common.base.Predicate;
-import com.google.common.cache.LoadingCache;
 import com.google.inject.Key;
 import com.google.inject.Module;
 import com.google.inject.TypeLiteral;
@@ -54,19 +52,17 @@ import com.google.inject.name.Names;
 @Test(groups = "live", singleThreaded = true, testName = "AzureComputeServiceLiveTest")
 public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest {
    
-   private LoadingCache<String, ResourceGroup> resourceGroupMap;
    private Predicate<URI> resourceDeleted;
+   private String resourceGroupName;
 
    public AzureComputeServiceLiveTest() {
       provider = "azurecompute-arm";
+      resourceGroupName = getClass().getSimpleName().toLowerCase();
    }
 
    @Override
    public void initializeContext() {
       super.initializeContext();
-      resourceGroupMap = context.utils().injector()
-            .getInstance(Key.get(new TypeLiteral<LoadingCache<String, ResourceGroup>>() {
-            }));
       resourceDeleted = context.utils().injector().getInstance(Key.get(new TypeLiteral<Predicate<URI>>() {
       }, Names.named(TIMEOUT_RESOURCE_DELETED)));
    }
@@ -75,16 +71,10 @@ public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest {
    @AfterClass(groups = "live", alwaysRun = true)
    protected void tearDownContext() {
       try {
-         if (template != null) {
-            ResourceGroup rg = resourceGroupMap.getIfPresent(template.getLocation().getId());
-            if (rg != null) {
-               AzureComputeApi api = view.unwrapApi(AzureComputeApi.class);
-               URI uri = api.getResourceGroupApi().delete(rg.name());
-               if (uri != null) {
-                  assertTrue(resourceDeleted.apply(uri),
-                        String.format("Resource %s was not terminated in the configured timeout", uri));
-               }
-            }
+         URI uri = view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().delete(resourceGroupName);
+         if (uri != null) {
+            assertTrue(resourceDeleted.apply(uri),
+                  String.format("Resource %s was not terminated in the configured timeout", uri));
          }
       } finally {
          super.tearDownContext();
@@ -109,7 +99,7 @@ public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest {
    @Override
    protected Properties setupProperties() {
       Properties properties = super.setupProperties();
-      AzureLiveTestUtils.defaultProperties(properties, getClass().getSimpleName().toLowerCase());
+      AzureLiveTestUtils.defaultProperties(properties);
       setIfTestSystemPropertyPresent(properties, "oauth.endpoint");
       return properties;
    }
@@ -117,7 +107,8 @@ public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest {
    @Override
    protected TemplateBuilder templateBuilder() {
       return super.templateBuilder().options(
-            authorizePublicKey(keyPair.get("public")).overrideLoginPrivateKey(keyPair.get("private")));
+            resourceGroup(resourceGroupName).authorizePublicKey(keyPair.get("public")).overrideLoginPrivateKey(
+                  keyPair.get("private")));
    }
 
    @Override

http://git-wip-us.apache.org/repos/asf/jclouds/blob/83c0a3c7/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureTemplateBuilderLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureTemplateBuilderLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureTemplateBuilderLiveTest.java
index d4cbdb0..b00aa05 100644
--- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureTemplateBuilderLiveTest.java
+++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureTemplateBuilderLiveTest.java
@@ -56,7 +56,7 @@ public class AzureTemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest {
    @Override
    protected Properties setupProperties() {
       Properties properties = super.setupProperties();
-      AzureLiveTestUtils.defaultProperties(properties, getClass().getSimpleName().toLowerCase());
+      AzureLiveTestUtils.defaultProperties(properties);
       setIfTestSystemPropertyPresent(properties, "oauth.endpoint");
       return properties;
    }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/83c0a3c7/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtensionLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtensionLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtensionLiveTest.java
index d708723..885269d 100644
--- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtensionLiveTest.java
+++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtensionLiveTest.java
@@ -16,7 +16,7 @@
  */
 package org.jclouds.azurecompute.arm.compute.extensions;
 
-import static org.jclouds.compute.options.TemplateOptions.Builder.authorizePublicKey;
+import static org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions.Builder.resourceGroup;
 import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED;
 import static org.jclouds.compute.options.RunScriptOptions.Builder.wrapInInitScript;
 import static org.testng.Assert.assertEquals;
@@ -28,7 +28,6 @@ import java.util.Properties;
 
 import org.jclouds.azurecompute.arm.AzureComputeApi;
 import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata;
-import org.jclouds.azurecompute.arm.domain.ResourceGroup;
 import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils;
 import org.jclouds.compute.ComputeTestUtils;
 import org.jclouds.compute.domain.ExecResponse;
@@ -43,7 +42,6 @@ import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
 import com.google.common.base.Predicate;
-import com.google.common.cache.LoadingCache;
 import com.google.inject.Key;
 import com.google.inject.Module;
 import com.google.inject.TypeLiteral;
@@ -56,30 +54,27 @@ import com.google.inject.name.Names;
 @Test(groups = "live", singleThreaded = true, testName = "AzureComputeImageExtensionLiveTest")
 public class AzureComputeImageExtensionLiveTest extends BaseImageExtensionLiveTest {
 
-   private LoadingCache<String, ResourceGroup> resourceGroupMap;
    private Predicate<URI> resourceDeleted;
-   private ResourceGroup testResourceGroup;
+   private String resourceGroupName;
    
    public AzureComputeImageExtensionLiveTest() {
       provider = "azurecompute-arm";
+      resourceGroupName = getClass().getSimpleName().toLowerCase();
    }
    
    @BeforeClass(groups = { "integration", "live" })
    public void setupContext() {
       super.setupContext();
-      resourceGroupMap = context.utils().injector()
-            .getInstance(Key.get(new TypeLiteral<LoadingCache<String, ResourceGroup>>() {
-            }));
       resourceDeleted = context.utils().injector().getInstance(Key.get(new TypeLiteral<Predicate<URI>>() {
       }, Names.named(TIMEOUT_RESOURCE_DELETED)));
-      createResourceGroup();
+      createResourceGroup(resourceGroupName);
    }
    
    @AfterClass(groups = { "integration", "live" })
    @Override
    protected void tearDownContext() {
       try {
-         URI uri = view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().delete(testResourceGroup.name());
+         URI uri = view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().delete(resourceGroupName);
          if (uri != null) {
             assertTrue(resourceDeleted.apply(uri),
                   String.format("Resource %s was not terminated in the configured timeout", uri));
@@ -108,7 +103,7 @@ public class AzureComputeImageExtensionLiveTest extends BaseImageExtensionLiveTe
    @Override
    protected Properties setupProperties() {
       Properties properties = super.setupProperties();
-      AzureLiveTestUtils.defaultProperties(properties, getClass().getSimpleName().toLowerCase());
+      AzureLiveTestUtils.defaultProperties(properties);
       setIfTestSystemPropertyPresent(properties, "oauth.endpoint");
       return properties;
    }
@@ -122,11 +117,12 @@ public class AzureComputeImageExtensionLiveTest extends BaseImageExtensionLiveTe
    public TemplateBuilder getNodeTemplate() {
       Map<String, String> keyPair = ComputeTestUtils.setupKeyPair();
       return super.getNodeTemplate().options(
-            authorizePublicKey(keyPair.get("public")).overrideLoginPrivateKey(keyPair.get("private")));
+            resourceGroup(resourceGroupName).authorizePublicKey(keyPair.get("public")).overrideLoginPrivateKey(
+                  keyPair.get("private")));
    }
 
-   private void createResourceGroup() {
+   private void createResourceGroup(String name) {
       Location location = getNodeTemplate().build().getLocation();
-      testResourceGroup = resourceGroupMap.getUnchecked(location.getId());
+      view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().create(name, location.getId(), null);
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/83c0a3c7/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java
index e00880b..153df29 100644
--- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java
+++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java
@@ -18,9 +18,8 @@ package org.jclouds.azurecompute.arm.compute.extensions;
 
 import static com.google.common.collect.Iterables.get;
 import static com.google.common.collect.Iterables.getOnlyElement;
+import static org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions.Builder.resourceGroup;
 import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED;
-import static org.jclouds.compute.options.TemplateOptions.Builder.inboundPorts;
-import static org.jclouds.compute.options.TemplateOptions.Builder.securityGroups;
 import static org.jclouds.compute.predicates.NodePredicates.inGroup;
 import static org.jclouds.net.domain.IpProtocol.TCP;
 import static org.testng.Assert.assertEquals;
@@ -34,12 +33,13 @@ import java.util.concurrent.ExecutionException;
 
 import org.jclouds.azurecompute.arm.AzureComputeApi;
 import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata;
-import org.jclouds.azurecompute.arm.domain.ResourceGroup;
+import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions;
 import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils;
 import org.jclouds.compute.ComputeService;
 import org.jclouds.compute.RunNodesException;
 import org.jclouds.compute.domain.NodeMetadata;
 import org.jclouds.compute.domain.SecurityGroup;
+import org.jclouds.compute.domain.Template;
 import org.jclouds.compute.extensions.SecurityGroupExtension;
 import org.jclouds.compute.extensions.internal.BaseSecurityGroupExtensionLiveTest;
 import org.jclouds.domain.Location;
@@ -52,7 +52,6 @@ import org.testng.annotations.Test;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
-import com.google.common.cache.LoadingCache;
 import com.google.inject.Key;
 import com.google.inject.TypeLiteral;
 import com.google.inject.name.Names;
@@ -64,23 +63,20 @@ import com.google.inject.name.Names;
 @Test(groups = "live", singleThreaded = true, testName = "AzureComputeSecurityGroupExtensionLiveTest")
 public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGroupExtensionLiveTest {
 
-   private LoadingCache<String, ResourceGroup> resourceGroupMap;
    private Predicate<URI> resourceDeleted;
-   private ResourceGroup testResourceGroup;
+   private String resourceGroupName;
 
    public AzureComputeSecurityGroupExtensionLiveTest() {
       provider = "azurecompute-arm";
+      resourceGroupName = "sgelivetest";
    }
 
    @BeforeClass(groups = { "integration", "live" })
    public void setupContext() {
       super.setupContext();
-      resourceGroupMap = context.utils().injector()
-            .getInstance(Key.get(new TypeLiteral<LoadingCache<String, ResourceGroup>>() {
-            }));
       resourceDeleted = context.utils().injector().getInstance(Key.get(new TypeLiteral<Predicate<URI>>() {
       }, Names.named(TIMEOUT_RESOURCE_DELETED)));
-      createResourceGroup();
+      createResourceGroup(resourceGroupName);
    }
 
    @Test(groups = { "integration", "live" }, singleThreaded = true, dependsOnMethods = "testAddIpPermissionsFromSpec")
@@ -104,7 +100,8 @@ public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGrou
       Optional<SecurityGroupExtension> securityGroupExtension = computeService.getSecurityGroupExtension();
       assertTrue(securityGroupExtension.isPresent(), "security group extension was not present");
 
-      NodeMetadata node = getOnlyElement(computeService.createNodesInGroup(nodeGroup, 1, securityGroups(groupId)));
+      NodeMetadata node = getOnlyElement(computeService.createNodesInGroup(nodeGroup, 1,
+            options().securityGroups(groupId)));
 
       try {
          Set<SecurityGroup> groups = securityGroupExtension.get().listSecurityGroupsForNode(node.getId());
@@ -121,8 +118,8 @@ public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGrou
       Optional<SecurityGroupExtension> securityGroupExtension = computeService.getSecurityGroupExtension();
       assertTrue(securityGroupExtension.isPresent(), "security group extension was not present");
 
-      NodeMetadata node = getOnlyElement(computeService
-            .createNodesInGroup(nodeGroup, 1, inboundPorts(22, 23, 24, 8000)));
+      NodeMetadata node = getOnlyElement(computeService.createNodesInGroup(nodeGroup, 1,
+            options().inboundPorts(22, 23, 24, 8000)));
 
       try {
          Set<SecurityGroup> groups = securityGroupExtension.get().listSecurityGroupsForNode(node.getId());
@@ -141,7 +138,7 @@ public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGrou
    @Override
    protected void tearDownContext() {
       try {
-         URI uri = view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().delete(testResourceGroup.name());
+         URI uri = view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().delete(resourceGroupName);
          if (uri != null) {
             assertTrue(resourceDeleted.apply(uri),
                   String.format("Resource %s was not terminated in the configured timeout", uri));
@@ -154,7 +151,7 @@ public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGrou
    @Override
    protected Properties setupProperties() {
       Properties properties = super.setupProperties();
-      AzureLiveTestUtils.defaultProperties(properties, "sgelivetest");
+      AzureLiveTestUtils.defaultProperties(properties);
       setIfTestSystemPropertyPresent(properties, "oauth.endpoint");
       return properties;
    }
@@ -163,9 +160,18 @@ public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGrou
    protected ProviderMetadata createProviderMetadata() {
       return AzureComputeProviderMetadata.builder().build();
    }
+   
+   private AzureTemplateOptions options() {
+      return resourceGroup(resourceGroupName);
+   }
+   
+   @Override
+   public Template getNodeTemplate() {
+      return view.getComputeService().templateBuilder().options(options()).build();
+   }
 
-   private void createResourceGroup() {
+   private void createResourceGroup(String name) {
       Location location = getNodeTemplate().getLocation();
-      testResourceGroup = resourceGroupMap.getUnchecked(location.getId());
+      view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().create(name, location.getId(), null);
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/83c0a3c7/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/domain/IdReferenceTest.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/domain/IdReferenceTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/domain/IdReferenceTest.java
new file mode 100644
index 0000000..e5426d7
--- /dev/null
+++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/domain/IdReferenceTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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 static org.jclouds.azurecompute.arm.domain.IdReference.extractName;
+import static org.jclouds.azurecompute.arm.domain.IdReference.extractResourceGroup;
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+public class IdReferenceTest {
+
+   @Test
+   public void testExtractResourceGroup() {
+      assertEquals(extractResourceGroup(null), null);
+      assertEquals(extractResourceGroup(""), null);
+      assertEquals(
+            extractResourceGroup("/subscriptions/subscription/resourceGroups/jclouds-northeurope/providers/Microsoft.Compute/virtualMachines/resources-8c5"),
+            "jclouds-northeurope");
+      assertEquals(extractResourceGroup("/subscriptions/subscription/resourceGroups/jclouds-west"), "jclouds-west");
+      assertEquals(extractResourceGroup("/resourceGroups/jclouds-west2"), "jclouds-west2");
+      assertEquals(
+            extractResourceGroup("/resourceGroups/jclouds-northeurope2/providers/Microsoft.Compute/virtualMachines/resources-8c5"),
+            "jclouds-northeurope2");
+      assertEquals(extractResourceGroup("resourceGroups/jclouds-west2"), null);
+      assertEquals(
+            extractResourceGroup("resourceGroups/jclouds-northeurope2/providers/Microsoft.Compute/virtualMachines/resources-8c5"),
+            null);
+      assertEquals(
+            extractResourceGroup("/subscriptions/subscription/providers/Microsoft.Compute/virtualMachines/resources-8c5"),
+            null);
+      assertEquals(
+            extractResourceGroup("/subscriptions/subscription/resourceGroups//jclouds-northeurope/providers/Microsoft.Compute/virtualMachines/resources-8c5"),
+            null);
+   }
+
+   @Test
+   public void testExtractName() {
+      assertEquals(extractName(null), null);
+      assertEquals(extractName(""), "");
+      assertEquals(extractName("foo"), "foo");
+      assertEquals(extractName("/foo/bar"), "bar");
+      assertEquals(extractName("/foo/bar/"), "bar");
+      assertEquals(extractName("/foo/bar////"), "bar");
+      assertEquals(extractName("/foo///bar////"), "bar");
+      assertEquals(extractName("////bar"), "bar");
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/83c0a3c7/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ImageApiLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ImageApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ImageApiLiveTest.java
index d976258..15231fd 100644
--- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ImageApiLiveTest.java
+++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ImageApiLiveTest.java
@@ -24,7 +24,7 @@ import static org.jclouds.compute.predicates.NodePredicates.inGroup;
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
-
+import static org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions.Builder.resourceGroup;
 import java.net.URI;
 import java.util.Properties;
 
@@ -32,18 +32,15 @@ import org.jclouds.azurecompute.arm.AzureComputeApi;
 import org.jclouds.azurecompute.arm.domain.IdReference;
 import org.jclouds.azurecompute.arm.domain.Image;
 import org.jclouds.azurecompute.arm.domain.ImageProperties;
-import org.jclouds.azurecompute.arm.domain.ResourceGroup;
 import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils;
 import org.jclouds.compute.RunNodesException;
 import org.jclouds.compute.domain.NodeMetadata;
 import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest;
-import org.jclouds.domain.Location;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
 import com.google.common.base.Predicate;
-import com.google.common.cache.LoadingCache;
 import com.google.inject.Key;
 import com.google.inject.TypeLiteral;
 import com.google.inject.name.Names;
@@ -54,11 +51,9 @@ public class ImageApiLiveTest extends BaseComputeServiceContextLiveTest {
 
    private static final String imageName = "imageFromRest";
 
-   private LoadingCache<String, ResourceGroup> resourceGroupMap;
    private Predicate<URI> resourceDeleted;
    private AzureComputeApi api;
 
-   private String resourceGroupName;
    private String location;
    private ImageApi imageApi;
    private Image image;
@@ -73,7 +68,7 @@ public class ImageApiLiveTest extends BaseComputeServiceContextLiveTest {
    @Override
    protected Properties setupProperties() {
       Properties properties = super.setupProperties();
-      AzureLiveTestUtils.defaultProperties(properties, getClass().getSimpleName().toLowerCase());
+      AzureLiveTestUtils.defaultProperties(properties);
       checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint");
       return properties;
    }
@@ -83,9 +78,6 @@ public class ImageApiLiveTest extends BaseComputeServiceContextLiveTest {
       super.initializeContext();
       resourceDeleted = context.utils().injector().getInstance(Key.get(new TypeLiteral<Predicate<URI>>() {
       }, Names.named(TIMEOUT_RESOURCE_DELETED)));
-      resourceGroupMap = context.utils().injector()
-            .getInstance(Key.get(new TypeLiteral<LoadingCache<String, ResourceGroup>>() {
-            }));
       api = view.unwrapApi(AzureComputeApi.class);
    }
 
@@ -94,10 +86,9 @@ public class ImageApiLiveTest extends BaseComputeServiceContextLiveTest {
    public void setupContext() {
       super.setupContext();
       // Use the resource name conventions used in the abstraction
-      ResourceGroup resourceGroup = createResourceGroup();
-      resourceGroupName = resourceGroup.name();
-      location = resourceGroup.location();
-      imageApi = api.getVirtualMachineImageApi(resourceGroupName);
+      location = view.getComputeService().templateBuilder().build().getLocation().getId();
+      view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().create(group, location, null);
+      imageApi = api.getVirtualMachineImageApi(group);
    }
 
    @Override
@@ -107,7 +98,7 @@ public class ImageApiLiveTest extends BaseComputeServiceContextLiveTest {
          view.getComputeService().destroyNodesMatching(inGroup(group));
       } finally {
          try {
-            URI uri = api.getResourceGroupApi().delete(resourceGroupName);
+            URI uri = api.getResourceGroupApi().delete(group);
             assertResourceDeleted(uri);
          } finally {
             super.tearDownContext();
@@ -122,11 +113,11 @@ public class ImageApiLiveTest extends BaseComputeServiceContextLiveTest {
 
    @Test
    public void testCreateImage() throws RunNodesException {
-      NodeMetadata node = getOnlyElement(view.getComputeService().createNodesInGroup(group, 1));
+      NodeMetadata node = getOnlyElement(view.getComputeService().createNodesInGroup(group, 1, resourceGroup(group)));
       IdReference vmIdRef = IdReference.create(node.getProviderId());
       view.getComputeService().suspendNode(node.getId());
 
-      api.getVirtualMachineApi(resourceGroupName).generalize(node.getName());
+      api.getVirtualMachineApi(group).generalize(node.getName());
 
       image = imageApi.createOrUpdate(imageName, location, ImageProperties.builder()
             .sourceVirtualMachine(vmIdRef).build());
@@ -161,9 +152,4 @@ public class ImageApiLiveTest extends BaseComputeServiceContextLiveTest {
       }
    }
 
-   private ResourceGroup createResourceGroup() {
-      Location location = view.getComputeService().templateBuilder().build().getLocation();
-      return resourceGroupMap.getUnchecked(location.getId());
-   }
-
 }