Repository: jclouds-labs
Updated Branches:
  refs/heads/resource-group-location [created] b1a8efcc8


Create one resource group in each region


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

Branch: refs/heads/resource-group-location
Commit: e6785463078003cb96f75a558436603a9d380a0f
Parents: 2f11038
Author: Ignasi Barrera <n...@apache.org>
Authored: Fri Oct 14 17:51:42 2016 +0200
Committer: Ignasi Barrera <n...@apache.org>
Committed: Fri Oct 14 17:51:42 2016 +0200

----------------------------------------------------------------------
 .../arm/AzureComputeProviderMetadata.java       |   6 +-
 .../arm/compute/AzureComputeServiceAdapter.java |  70 ++++++++----
 .../AzureComputeServiceContextModule.java       | 110 ++++++++++---------
 .../extensions/AzureComputeImageExtension.java  |  24 ++--
 .../functions/LocationToResourceGroupName.java  |  46 ++++++++
 .../ResourceDefinitionToCustomImage.java        |  15 ++-
 .../functions/VirtualMachineToNodeMetadata.java |  16 ++-
 .../CreateResourceGroupThenCreateNodes.java     |  12 +-
 .../arm/config/AzureComputeProperties.java      |   2 -
 .../azurecompute/arm/domain/RegionAndId.java    |  50 +++++++++
 .../arm/functions/CleanupResources.java         |  38 +++----
 .../compute/AzureComputeServiceLiveTest.java    |   4 +-
 .../compute/AzureTemplateBuilderLiveTest.java   |   4 +-
 .../AzureComputeImageExtensionLiveTest.java     |   4 +-
 14 files changed, 266 insertions(+), 135 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e6785463/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeProviderMetadata.java
----------------------------------------------------------------------
diff --git 
a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeProviderMetadata.java
 
b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeProviderMetadata.java
index a434079..beac925 100644
--- 
a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeProviderMetadata.java
+++ 
b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeProviderMetadata.java
@@ -25,12 +25,13 @@ import static 
org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_P
 import static 
org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATION_POLL_INITIAL_PERIOD;
 import static 
org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATION_POLL_MAX_PERIOD;
 import static 
org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATION_TIMEOUT;
-import static 
org.jclouds.azurecompute.arm.config.AzureComputeProperties.RESOURCE_GROUP_NAME;
 import static 
org.jclouds.azurecompute.arm.config.AzureComputeProperties.STORAGE_API_VERSION;
 import static 
org.jclouds.azurecompute.arm.config.AzureComputeProperties.TCP_RULE_FORMAT;
 import static 
org.jclouds.azurecompute.arm.config.AzureComputeProperties.TCP_RULE_REGEXP;
 import static 
org.jclouds.compute.config.ComputeServiceProperties.IMAGE_AUTHENTICATE_SUDO;
 import static 
org.jclouds.compute.config.ComputeServiceProperties.IMAGE_LOGIN_USER;
+import static 
org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_DELIMITER;
+import static 
org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_PREFIX;
 import static org.jclouds.compute.config.ComputeServiceProperties.TEMPLATE;
 import static 
org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED;
 import static 
org.jclouds.oauth.v2.config.CredentialType.CLIENT_CREDENTIALS_SECRET;
@@ -88,9 +89,10 @@ public class AzureComputeProviderMetadata extends 
BaseProviderMetadata {
       properties.setProperty(TCP_RULE_REGEXP, "tcp_\\d{1,5}-\\d{1,5}");
       properties.put(RESOURCE, "https://management.azure.com/";);
       properties.put(CREDENTIAL_TYPE, CLIENT_CREDENTIALS_SECRET.toString());
-      properties.put(RESOURCE_GROUP_NAME, "jclouds");
       properties.put(DEFAULT_VNET_ADDRESS_SPACE_PREFIX, "10.0.0.0/16");
       properties.put(DEFAULT_SUBNET_ADDRESS_PREFIX, "10.0.0.0/24");
+      properties.put(RESOURCENAME_PREFIX, "jclouds");
+      properties.put(RESOURCENAME_DELIMITER, "-");
       properties.put(DEFAULT_DATADISKSIZE, "100");
       properties.put(IMAGE_PUBLISHERS, "Canonical,RedHat");
       // Default credentials for all images

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e6785463/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 0e2ed64..94f255c 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
@@ -30,11 +30,12 @@ import java.util.List;
 import java.util.Set;
 
 import javax.inject.Inject;
-import javax.inject.Named;
 import javax.inject.Singleton;
 
 import org.jclouds.azurecompute.arm.AzureComputeApi;
 import 
org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.AzureComputeConstants;
+import 
org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.PublicIpAvailablePredicateFactory;
+import 
org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupName;
 import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions;
 import org.jclouds.azurecompute.arm.domain.DataDisk;
 import org.jclouds.azurecompute.arm.domain.HardwareProfile;
@@ -51,6 +52,8 @@ import org.jclouds.azurecompute.arm.domain.OSProfile;
 import org.jclouds.azurecompute.arm.domain.Offer;
 import org.jclouds.azurecompute.arm.domain.PublicIPAddress;
 import org.jclouds.azurecompute.arm.domain.PublicIPAddressProperties;
+import org.jclouds.azurecompute.arm.domain.RegionAndId;
+import org.jclouds.azurecompute.arm.domain.ResourceGroup;
 import org.jclouds.azurecompute.arm.domain.ResourceProviderMetaData;
 import org.jclouds.azurecompute.arm.domain.SKU;
 import org.jclouds.azurecompute.arm.domain.StorageProfile;
@@ -92,23 +95,24 @@ import com.google.common.collect.Lists;
 @Singleton
 public class AzureComputeServiceAdapter implements 
ComputeServiceAdapter<VirtualMachine, VMHardware, VMImage, Location> {
 
-   private final String azureGroup;
    private final CleanupResources cleanupResources;
    private final AzureComputeApi api;
    private final AzureComputeConstants azureComputeConstants;
    private final Supplier<Set<String>> regionIds;
-   private final Predicate<String> publicIpAvailable;
+   private final PublicIpAvailablePredicateFactory publicIpAvailable;
+   private final LocationToResourceGroupName locationToResourceGroupName;
 
    @Inject
    AzureComputeServiceAdapter(final AzureComputeApi api, final 
AzureComputeConstants azureComputeConstants,
          CleanupResources cleanupResources, @Region Supplier<Set<String>> 
regionIds,
-         @Named("PublicIpAvailable") Predicate<String> publicIpAvailable) {
+         PublicIpAvailablePredicateFactory publicIpAvailable,
+         LocationToResourceGroupName locationToResourceGroupName) {
       this.api = api;
       this.azureComputeConstants = azureComputeConstants;
-      this.azureGroup = azureComputeConstants.azureResourceGroup();
       this.cleanupResources = cleanupResources;
       this.regionIds = regionIds;
       this.publicIpAvailable = publicIpAvailable;
+      this.locationToResourceGroupName = locationToResourceGroupName;
    }
 
    @Override
@@ -116,6 +120,7 @@ public class AzureComputeServiceAdapter implements 
ComputeServiceAdapter<Virtual
            final String group, final String name, final Template template) {
 
       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
@@ -125,7 +130,7 @@ public class AzureComputeServiceAdapter implements 
ComputeServiceAdapter<Virtual
       
       String locationName = template.getLocation().getId();
       String subnetId = templateOptions.getSubnetId();
-      NetworkInterfaceCard nic = createNetworkInterfaceCard(subnetId, name, 
locationName); 
+      NetworkInterfaceCard nic = createNetworkInterfaceCard(subnetId, name, 
locationName, azureGroup);
       StorageProfile storageProfile = createStorageProfile(name, 
template.getImage(), templateOptions.getBlob());
       HardwareProfile hardwareProfile = 
HardwareProfile.builder().vmSize(template.getHardware().getId()).build();
       OSProfile osProfile = createOsProfile(name, template);
@@ -202,21 +207,26 @@ public class AzureComputeServiceAdapter implements 
ComputeServiceAdapter<Virtual
       for (Location location : listLocations()){
          osImages.addAll(listImagesByLocation(location.name()));
       }
+      
       // list custom images
-      List<StorageService> storages = 
api.getStorageAccountApi(azureGroup).list();
-      for (StorageService storage : storages) {
-         String name = storage.name();
-         StorageService storageService = 
api.getStorageAccountApi(azureGroup).get(name);
-         if (storageService != null
-               && Status.Succeeded == 
storageService.storageServiceProperties().provisioningState()) {
-            String key = 
api.getStorageAccountApi(azureGroup).getKeys(name).key1();
-            BlobHelper blobHelper = new BlobHelper(storage.name(), key);
-            try {
-               List<VMImage> images = blobHelper.getImages(CONTAINER_NAME, 
azureGroup, CUSTOM_IMAGE_OFFER,
-                     storage.location());
-               osImages.addAll(images);
-            } finally {
-               closeQuietly(blobHelper);
+      for (ResourceGroup resourceGroup : api.getResourceGroupApi().list()) {
+         String azureGroup = resourceGroup.name();
+         List<StorageService> storages = 
api.getStorageAccountApi(azureGroup).list();
+         
+         for (StorageService storage : storages) {
+            String name = storage.name();
+            StorageService storageService = 
api.getStorageAccountApi(azureGroup).get(name);
+            if (storageService != null
+                  && Status.Succeeded == 
storageService.storageServiceProperties().provisioningState()) {
+               String key = 
api.getStorageAccountApi(azureGroup).getKeys(name).key1();
+               BlobHelper blobHelper = new BlobHelper(storage.name(), key);
+               try {
+                  List<VMImage> images = blobHelper.getImages(CONTAINER_NAME, 
azureGroup, CUSTOM_IMAGE_OFFER,
+                        storage.location());
+                  osImages.addAll(images);
+               } finally {
+                  closeQuietly(blobHelper);
+               }
             }
          }
       }
@@ -227,6 +237,8 @@ public class AzureComputeServiceAdapter implements 
ComputeServiceAdapter<Virtual
    @Override
    public VMImage getImage(final String id) {
       VMImage image = decodeFieldsFromUniqueId(id);
+      String azureGroup = locationToResourceGroupName.apply(image.location());
+      
       if (image.custom()) {
          VMImage customImage = null;
          StorageServiceKeys keys = 
api.getStorageAccountApi(azureGroup).getKeys(image.storage());
@@ -303,6 +315,8 @@ public class AzureComputeServiceAdapter implements 
ComputeServiceAdapter<Virtual
 
    @Override
    public VirtualMachine getNode(final String id) {
+      RegionAndId regionAndId = RegionAndId.fromSlashEncoded(id);
+      String azureGroup = 
locationToResourceGroupName.apply(regionAndId.region());
       return api.getVirtualMachineApi(azureGroup).get(id);
    }
 
@@ -313,22 +327,32 @@ public class AzureComputeServiceAdapter implements 
ComputeServiceAdapter<Virtual
 
    @Override
    public void rebootNode(final String id) {
+      RegionAndId regionAndId = RegionAndId.fromSlashEncoded(id);
+      String azureGroup = 
locationToResourceGroupName.apply(regionAndId.region());
       api.getVirtualMachineApi(azureGroup).restart(id);
    }
 
    @Override
    public void resumeNode(final String id) {
+      RegionAndId regionAndId = RegionAndId.fromSlashEncoded(id);
+      String azureGroup = 
locationToResourceGroupName.apply(regionAndId.region());
       api.getVirtualMachineApi(azureGroup).start(id);
    }
 
    @Override
    public void suspendNode(final String id) {
+      RegionAndId regionAndId = RegionAndId.fromSlashEncoded(id);
+      String azureGroup = 
locationToResourceGroupName.apply(regionAndId.region());
       api.getVirtualMachineApi(azureGroup).stop(id);
    }
 
    @Override
    public Iterable<VirtualMachine> listNodes() {
-      return api.getVirtualMachineApi(azureGroup).list();
+      ImmutableList.Builder<VirtualMachine> nodes = ImmutableList.builder();
+      for (ResourceGroup resourceGroup : api.getResourceGroupApi().list()) {
+         nodes.addAll(api.getVirtualMachineApi(resourceGroup.name()).list());
+      }
+      return nodes.build();
    }
 
    @Override
@@ -364,7 +388,7 @@ public class AzureComputeServiceAdapter implements 
ComputeServiceAdapter<Virtual
       return builder.build();
    }
 
-   private NetworkInterfaceCard createNetworkInterfaceCard(String subnetId, 
String name, String locationName) {
+   private NetworkInterfaceCard createNetworkInterfaceCard(String subnetId, 
String name, String locationName, String azureGroup) {
       final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(azureGroup);
 
       PublicIPAddressProperties properties =
@@ -376,7 +400,7 @@ public class AzureComputeServiceAdapter implements 
ComputeServiceAdapter<Virtual
       String publicIpAddressName = "public-address-" + name;
       PublicIPAddress ip = ipApi.createOrUpdate(publicIpAddressName, 
locationName, ImmutableMap.of("jclouds", name), properties);
       
-      checkState(publicIpAvailable.apply(publicIpAddressName),
+      
checkState(publicIpAvailable.create(azureGroup).apply(publicIpAddressName),
             "Public IP was not provisioned in the configured timeout");
 
       final NetworkInterfaceCardProperties networkInterfaceCardProperties =

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e6785463/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/config/AzureComputeServiceContextModule.java
----------------------------------------------------------------------
diff --git 
a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/config/AzureComputeServiceContextModule.java
 
b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/config/AzureComputeServiceContextModule.java
index 24f02ea..34a5160 100644
--- 
a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/config/AzureComputeServiceContextModule.java
+++ 
b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/config/AzureComputeServiceContextModule.java
@@ -24,7 +24,6 @@ import static 
org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_P
 import static 
org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATION_POLL_INITIAL_PERIOD;
 import static 
org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATION_POLL_MAX_PERIOD;
 import static 
org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATION_TIMEOUT;
-import static 
org.jclouds.azurecompute.arm.config.AzureComputeProperties.RESOURCE_GROUP_NAME;
 import static 
org.jclouds.azurecompute.arm.config.AzureComputeProperties.TCP_RULE_FORMAT;
 import static 
org.jclouds.azurecompute.arm.config.AzureComputeProperties.TCP_RULE_REGEXP;
 import static 
org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED;
@@ -137,10 +136,6 @@ public class AzureComputeServiceContextModule
       @Inject
       private String tcpRuleRegexpProperty;
 
-      @Named(RESOURCE_GROUP_NAME)
-      @Inject
-      private String azureResourceGroupProperty;
-
       @Named(IMAGE_PUBLISHERS)
       @Inject
       private String azureImagePublishersProperty;
@@ -161,10 +156,6 @@ public class AzureComputeServiceContextModule
          return Long.parseLong(operationTimeoutProperty);
       }
 
-      public String azureResourceGroup() {
-         return azureResourceGroupProperty;
-      }
-
       public String azureImagePublishers() {
          return azureImagePublishersProperty;
       }
@@ -199,11 +190,11 @@ public class AzureComputeServiceContextModule
    }
 
    @Provides
-   @com.google.inject.name.Named(TIMEOUT_NODE_RUNNING)
-   protected Predicate<String> provideVirtualMachineRunningPredicate(final 
AzureComputeApi api, final 
AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants, 
Timeouts timeouts, PollPeriod pollPeriod) {
-      String azureGroup = azureComputeConstants.azureResourceGroup();
-      return retry(new VirtualMachineInStatePredicate(api, azureGroup, 
PowerState.RUNNING), timeouts.nodeRunning,
-              pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod);
+   @Named(TIMEOUT_NODE_RUNNING)
+   protected VirtualMachineInStatePredicateFactory 
provideVirtualMachineRunningPredicate(final AzureComputeApi api,
+         Timeouts timeouts, PollPeriod pollPeriod) {
+      return new VirtualMachineInStatePredicateFactory(api, 
PowerState.RUNNING, timeouts.nodeRunning,
+            pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod);
    }
    
    @Provides
@@ -229,19 +220,17 @@ public class AzureComputeServiceContextModule
 
    @Provides
    @Named(TIMEOUT_NODE_SUSPENDED)
-   protected Predicate<String> provideNodeSuspendedPredicate(final 
AzureComputeApi api, final 
AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants,
-                                                             Timeouts 
timeouts, PollPeriod pollPeriod) {
-      String azureGroup = azureComputeConstants.azureResourceGroup();
-      return retry(new VirtualMachineInStatePredicate(api, azureGroup, 
PowerState.STOPPED), timeouts.nodeTerminated,
-              pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod);
+   protected VirtualMachineInStatePredicateFactory 
provideNodeSuspendedPredicate(final AzureComputeApi api,
+         Timeouts timeouts, PollPeriod pollPeriod) {
+      return new VirtualMachineInStatePredicateFactory(api, 
PowerState.STOPPED, timeouts.nodeTerminated,
+            pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod);
    }
    
    @Provides
-   @Named("PublicIpAvailable")
-   protected Predicate<String> providePublicIpAvailablePredicate(final 
AzureComputeApi api, final 
AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants,
-                                                             Timeouts 
timeouts, PollPeriod pollPeriod) {
-      String azureGroup = azureComputeConstants.azureResourceGroup();
-      return retry(new PublicIpAvailablePredicate(api, azureGroup), 
azureComputeConstants.operationTimeout(),
+   protected PublicIpAvailablePredicateFactory 
providePublicIpAvailablePredicate(final AzureComputeApi api,
+         final AzureComputeServiceContextModule.AzureComputeConstants 
azureComputeConstants, Timeouts timeouts,
+         PollPeriod pollPeriod) {
+      return new PublicIpAvailablePredicateFactory(api, 
azureComputeConstants.operationTimeout(),
             azureComputeConstants.operationPollInitialPeriod(), 
azureComputeConstants.operationPollMaxPeriod());
    }
 
@@ -280,45 +269,62 @@ public class AzureComputeServiceContextModule
       }
    }
 
-   @VisibleForTesting
-   static class VirtualMachineInStatePredicate implements Predicate<String> {
+   public static class VirtualMachineInStatePredicateFactory {
 
       private final AzureComputeApi api;
-      private final String azureGroup;
       private final PowerState powerState;
-
-      public VirtualMachineInStatePredicate(AzureComputeApi api, String 
azureGroup, PowerState powerState) {
-         this.api = checkNotNull(api, "api must not be null");
-         this.azureGroup = checkNotNull(azureGroup, "azuregroup must not be 
null");
-         this.powerState = checkNotNull(powerState, "powerState must not be 
null");
+      private final long timeout;
+      private final long period;
+      private final long maxPeriod;
+
+      VirtualMachineInStatePredicateFactory(AzureComputeApi api, PowerState 
powerState, long timeout,
+            long period, long maxPeriod) {
+         this.api = checkNotNull(api, "api cannot be null");
+         this.powerState = checkNotNull(powerState, "powerState cannot be 
null");
+         this.timeout = timeout;
+         this.period = period;
+         this.maxPeriod = maxPeriod;
       }
 
-      @Override
-      public boolean apply(String name) {
-         checkNotNull(name, "name cannot be null");
-         VirtualMachineInstance vmInstance = 
api.getVirtualMachineApi(this.azureGroup).getInstanceDetails(name);
-         if (vmInstance == null) return false;
-         return powerState == vmInstance.powerState();
+      public Predicate<String> create(final String azureGroup) {
+         return retry(new Predicate<String>() {
+            @Override
+            public boolean apply(String name) {
+               checkNotNull(name, "name cannot be null");
+               VirtualMachineInstance vmInstance = 
api.getVirtualMachineApi(azureGroup).getInstanceDetails(name);
+               if (vmInstance == null)
+                  return false;
+               return powerState == vmInstance.powerState();
+            }
+         }, timeout, period, maxPeriod);
       }
    }
    
-   @VisibleForTesting
-   static class PublicIpAvailablePredicate implements Predicate<String> {
+   public static class PublicIpAvailablePredicateFactory {
 
       private final AzureComputeApi api;
-      private final String azureGroup;
-
-      public PublicIpAvailablePredicate(AzureComputeApi api, String 
azureGroup) {
-         this.api = checkNotNull(api, "api must not be null");
-         this.azureGroup = checkNotNull(azureGroup, "azuregroup must not be 
null");
+      private final long timeout;
+      private final long period;
+      private final long maxPeriod;
+
+      PublicIpAvailablePredicateFactory(AzureComputeApi api, long timeout,
+            long period, long maxPeriod) {
+         this.api = checkNotNull(api, "api cannot be null");
+         this.timeout = timeout;
+         this.period = period;
+         this.maxPeriod = maxPeriod;
       }
-
-      @Override
-      public boolean apply(String name) {
-         checkNotNull(name, "name cannot be null");
-         PublicIPAddress publicIp = 
api.getPublicIPAddressApi(azureGroup).get(name);
-         if (publicIp == null) return false;
-         return 
publicIp.properties().provisioningState().equalsIgnoreCase("Succeeded");
+      
+      public Predicate<String> create(final String azureGroup) {
+         return retry(new Predicate<String>() {
+            @Override
+            public boolean apply(String name) {
+               checkNotNull(name, "name cannot be null");
+               PublicIPAddress publicIp = 
api.getPublicIPAddressApi(azureGroup).get(name);
+               if (publicIp == null) return false;
+               return 
publicIp.properties().provisioningState().equalsIgnoreCase("Succeeded");
+            }
+         }, timeout, period, maxPeriod);
       }
    }
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e6785463/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtension.java
----------------------------------------------------------------------
diff --git 
a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtension.java
 
b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtension.java
index 99c9c6c..7f163c5 100644
--- 
a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtension.java
+++ 
b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtension.java
@@ -31,8 +31,10 @@ import javax.annotation.Resource;
 
 import org.jclouds.Constants;
 import org.jclouds.azurecompute.arm.AzureComputeApi;
-import 
org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.AzureComputeConstants;
+import 
org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.VirtualMachineInStatePredicateFactory;
+import 
org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupName;
 import 
org.jclouds.azurecompute.arm.compute.functions.ResourceDefinitionToCustomImage;
+import org.jclouds.azurecompute.arm.domain.RegionAndId;
 import org.jclouds.azurecompute.arm.domain.ResourceDefinition;
 import org.jclouds.azurecompute.arm.domain.StorageServiceKeys;
 import org.jclouds.azurecompute.arm.domain.VMImage;
@@ -61,27 +63,27 @@ public class AzureComputeImageExtension implements 
ImageExtension {
    protected Logger logger = Logger.NULL;
 
    private final AzureComputeApi api;
-   private final String group;
    private final ListeningExecutorService userExecutor;
    private final Predicate<URI> imageAvailablePredicate;
-   private final Predicate<String> nodeSuspendedPredicate;
+   private final VirtualMachineInStatePredicateFactory nodeSuspendedPredicate;
    private final ResourceDefinitionToCustomImage.Factory 
resourceDefinitionToImage;
    private final CleanupResources cleanupResources;
+   private final LocationToResourceGroupName locationToResourceGroupName;
 
    @Inject
    AzureComputeImageExtension(AzureComputeApi api,
          @Named(TIMEOUT_IMAGE_AVAILABLE) Predicate<URI> 
imageAvailablePredicate,
-         @Named(TIMEOUT_NODE_SUSPENDED) Predicate<String> 
nodeSuspendedPredicate,
-         AzureComputeConstants azureComputeConstants,
+         @Named(TIMEOUT_NODE_SUSPENDED) VirtualMachineInStatePredicateFactory 
nodeSuspendedPredicate,
          @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService 
userExecutor,
-         ResourceDefinitionToCustomImage.Factory resourceDefinitionToImage, 
CleanupResources cleanupResources) {
+         ResourceDefinitionToCustomImage.Factory resourceDefinitionToImage, 
CleanupResources cleanupResources,
+         LocationToResourceGroupName locationToResourceGroupName) {
       this.api = api;
       this.imageAvailablePredicate = imageAvailablePredicate;
       this.nodeSuspendedPredicate = nodeSuspendedPredicate;
-      this.group = azureComputeConstants.azureResourceGroup();
       this.userExecutor = userExecutor;
       this.resourceDefinitionToImage = resourceDefinitionToImage;
       this.cleanupResources = cleanupResources;
+      this.locationToResourceGroupName = locationToResourceGroupName;
    }
 
    @Override
@@ -94,10 +96,14 @@ public class AzureComputeImageExtension implements 
ImageExtension {
       final CloneImageTemplate cloneTemplate = (CloneImageTemplate) template;
       final String id = cloneTemplate.getSourceNodeId();
       final String name = cloneTemplate.getName();
+      
+      RegionAndId regionAndId = RegionAndId.fromSlashEncoded(id);
+      final String group = 
locationToResourceGroupName.apply(regionAndId.region());
 
       logger.debug(">> stopping node %s...", id);
       api.getVirtualMachineApi(group).stop(id);
-      checkState(nodeSuspendedPredicate.apply(id), "Node %s was not suspended 
within the configured time limit", id);
+      checkState(nodeSuspendedPredicate.create(group).apply(id),
+            "Node %s was not suspended within the configured time limit", id);
 
       return userExecutor.submit(new Callable<Image>() {
          @Override
@@ -130,7 +136,7 @@ public class AzureComputeImageExtension implements 
ImageExtension {
 
       StorageServiceKeys keys = 
api.getStorageAccountApi(image.group()).getKeys(image.storage());
       BlobHelper blobHelper = new BlobHelper(image.storage(), keys.key1());
-      
+
       try {
          // This removes now all the images in this storage. At least in 
theory,
          // there should be just one and if there is

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e6785463/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToResourceGroupName.java
----------------------------------------------------------------------
diff --git 
a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToResourceGroupName.java
 
b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToResourceGroupName.java
new file mode 100644
index 0000000..c97850a
--- /dev/null
+++ 
b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToResourceGroupName.java
@@ -0,0 +1,46 @@
+/*
+ * 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.functions;
+
+import static 
org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_DELIMITER;
+import static 
org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_PREFIX;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import com.google.common.base.Function;
+
+/**
+ * Returns the name of the resource group for the current location.
+ */
+public class LocationToResourceGroupName implements Function<String, String> {
+
+   private final String prefix;
+   private final char delimiter;
+
+   @Inject
+   LocationToResourceGroupName(@Named(RESOURCENAME_PREFIX) String prefix, 
@Named(RESOURCENAME_DELIMITER) char delimiter) {
+      this.prefix = prefix;
+      this.delimiter = delimiter;
+   }
+
+   @Override
+   public String apply(String input) {
+      return String.format("%s%s%s", prefix, delimiter, input);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e6785463/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/ResourceDefinitionToCustomImage.java
----------------------------------------------------------------------
diff --git 
a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/ResourceDefinitionToCustomImage.java
 
b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/ResourceDefinitionToCustomImage.java
index cce6b50..e2dae87 100644
--- 
a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/ResourceDefinitionToCustomImage.java
+++ 
b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/ResourceDefinitionToCustomImage.java
@@ -23,7 +23,7 @@ import java.util.Map;
 import javax.inject.Inject;
 
 import org.jclouds.azurecompute.arm.AzureComputeApi;
-import 
org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.AzureComputeConstants;
+import org.jclouds.azurecompute.arm.domain.RegionAndId;
 import org.jclouds.azurecompute.arm.domain.ResourceDefinition;
 import org.jclouds.azurecompute.arm.domain.VMImage;
 import org.jclouds.azurecompute.arm.domain.VirtualMachine;
@@ -39,21 +39,24 @@ public class ResourceDefinitionToCustomImage implements 
Function<ResourceDefinit
       ResourceDefinitionToCustomImage create(@Assisted("nodeId") String 
nodeId, @Assisted("imageName") String imageName);
    }
 
-   private final String resourceGroup;
    private final Function<VMImage, Image> vmImageToImage;
    private final String imageName;
    private final String storageAccountName;
    private final VirtualMachine vm;
+   private final String resourceGroup;
 
    @Inject
-   ResourceDefinitionToCustomImage(AzureComputeApi api, AzureComputeConstants 
azureComputeConstants,
+   ResourceDefinitionToCustomImage(AzureComputeApi api,
          StorageProfileToStorageAccountName storageProfileToStorageAccountName,
-         Function<VMImage, Image> vmImageToImage, @Assisted("nodeId") String 
nodeId,
+         Function<VMImage, Image> vmImageToImage, LocationToResourceGroupName 
locationToResourceGroupName,
+         @Assisted("nodeId") String nodeId,
          @Assisted("imageName") String imageName) {
       this.vmImageToImage = vmImageToImage;
-      this.resourceGroup = azureComputeConstants.azureResourceGroup();
       this.imageName = imageName;
-      this.vm = api.getVirtualMachineApi(resourceGroup).get(nodeId);
+      
+      RegionAndId regionAndId = RegionAndId.fromSlashEncoded(nodeId);
+      this.resourceGroup = 
locationToResourceGroupName.apply(regionAndId.region());
+      this.vm = api.getVirtualMachineApi(this.resourceGroup).get(nodeId);
       this.storageAccountName = 
storageProfileToStorageAccountName.apply(vm.properties().storageProfile());
    }
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e6785463/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 e151a4a..1f90870 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
@@ -38,6 +38,7 @@ import 
org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextMod
 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.RegionAndId;
 import org.jclouds.azurecompute.arm.domain.StorageProfile;
 import org.jclouds.azurecompute.arm.domain.StorageServiceKeys;
 import org.jclouds.azurecompute.arm.domain.VMImage;
@@ -110,7 +111,6 @@ public class VirtualMachineToNodeMetadata implements 
Function<VirtualMachine, No
                      .put(PowerState.UNRECOGNIZED, 
NodeMetadata.Status.UNRECOGNIZED).build(),
                NodeMetadata.Status.UNRECOGNIZED);
 
-   private final String azureGroup;
    private final AzureComputeApi api;
    private final GroupNamingConvention nodeNamingConvention;
    private final Supplier<Map<String, ? extends Image>> images;
@@ -119,28 +119,32 @@ public class VirtualMachineToNodeMetadata implements 
Function<VirtualMachine, No
    private final Map<String, Credentials> credentialStore;
    private final Function<VMImage, Image> vmImageToImge;
    private final StorageProfileToStorageAccountName 
storageProfileToStorageAccountName;
+   private final LocationToResourceGroupName locationToResourceGroupName;
 
    @Inject
    VirtualMachineToNodeMetadata(AzureComputeApi api, 
GroupNamingConvention.Factory namingConvention,
          Supplier<Map<String, ? extends Image>> images, Supplier<Map<String, ? 
extends Hardware>> hardwares,
          @Memoized Supplier<Set<? extends Location>> locations, Map<String, 
Credentials> credentialStore,
          final AzureComputeConstants azureComputeConstants, Function<VMImage, 
Image> vmImageToImge,
-         StorageProfileToStorageAccountName 
storageProfileToStorageAccountName) {
+         StorageProfileToStorageAccountName storageProfileToStorageAccountName,
+         LocationToResourceGroupName locationToResourceGroupName) {
       this.api = api;
       this.nodeNamingConvention = namingConvention.createWithoutPrefix();
       this.images = checkNotNull(images, "images cannot be null");
       this.locations = checkNotNull(locations, "locations cannot be null");
       this.hardwares = checkNotNull(hardwares, "hardwares cannot be null");
       this.credentialStore = credentialStore;
-      this.azureGroup = azureComputeConstants.azureResourceGroup();
       this.vmImageToImge = vmImageToImge;
       this.storageProfileToStorageAccountName = 
storageProfileToStorageAccountName;
+      this.locationToResourceGroupName = locationToResourceGroupName;
    }
 
    @Override
    public NodeMetadata apply(VirtualMachine virtualMachine) {
+      String azureGroup = 
locationToResourceGroupName.apply(virtualMachine.location());
+      
       NodeMetadataBuilder builder = new NodeMetadataBuilder();
-      builder.id(virtualMachine.name());
+      builder.id(RegionAndId.fromRegionAndId(virtualMachine.location(), 
virtualMachine.name()).slashEncode());
       builder.providerId(virtualMachine.id());
       builder.name(virtualMachine.name());
       builder.hostname(virtualMachine.name());
@@ -180,7 +184,7 @@ public class VirtualMachineToNodeMetadata implements 
Function<VirtualMachine, No
       String locationName = virtualMachine.location();
       builder.location(getLocation(locationName));
 
-      Optional<? extends Image> image = 
findImage(virtualMachine.properties().storageProfile(), locationName);
+      Optional<? extends Image> image = 
findImage(virtualMachine.properties().storageProfile(), locationName, 
azureGroup);
       if (image.isPresent()) {
          builder.imageId(image.get().getId());
          builder.operatingSystem(image.get().getOperatingSystem());
@@ -239,7 +243,7 @@ public class VirtualMachineToNodeMetadata implements 
Function<VirtualMachine, No
       }, null);
    }
 
-   protected Optional<? extends Image> findImage(final StorageProfile 
storageProfile, String locatioName) {
+   protected Optional<? extends Image> findImage(final StorageProfile 
storageProfile, String locatioName, String azureGroup) {
       if (storageProfile.imageReference() != null) {
          return Optional.fromNullable(images.get().get(
                encodeFieldsToUniqueId(false, locatioName, 
storageProfile.imageReference())));

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e6785463/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourceGroupThenCreateNodes.java
----------------------------------------------------------------------
diff --git 
a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourceGroupThenCreateNodes.java
 
b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourceGroupThenCreateNodes.java
index 99528fd..024204b 100644
--- 
a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourceGroupThenCreateNodes.java
+++ 
b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourceGroupThenCreateNodes.java
@@ -35,6 +35,7 @@ import javax.inject.Singleton;
 import org.jclouds.Constants;
 import org.jclouds.azurecompute.arm.AzureComputeApi;
 import 
org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule;
+import 
org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupName;
 import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions;
 import org.jclouds.azurecompute.arm.domain.ResourceGroup;
 import org.jclouds.azurecompute.arm.domain.StorageService;
@@ -73,20 +74,23 @@ public class CreateResourceGroupThenCreateNodes extends 
CreateNodesWithGroupEnco
 
    private final AzureComputeApi api;
    private final AzureComputeServiceContextModule.AzureComputeConstants 
azureComputeConstants;
+   private final LocationToResourceGroupName locationToResourceGroupName;
 
    @Inject
    protected CreateResourceGroupThenCreateNodes(
            CreateNodeWithGroupEncodedIntoName addNodeWithGroupStrategy,
            ListNodesStrategy listNodesStrategy,
            GroupNamingConvention.Factory namingConvention,
-           @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService 
userExecutor,
-           CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory 
customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory,
-           AzureComputeApi api, 
AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants) {
+         @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService 
userExecutor,
+         CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory 
customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory,
+         AzureComputeApi api, 
AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants,
+         LocationToResourceGroupName locationToResourceGroupName) {
       super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, 
userExecutor,
               customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory);
       this.api = checkNotNull(api, "api cannot be null");
       checkNotNull(userExecutor, "userExecutor cannot be null");
       this.azureComputeConstants = azureComputeConstants;
+      this.locationToResourceGroupName = locationToResourceGroupName;
    }
 
    @Override
@@ -100,7 +104,7 @@ public class CreateResourceGroupThenCreateNodes extends 
CreateNodesWithGroupEnco
          logger.warn(">> a runScript was configured but no SSH key has been 
provided. " +
                  "Authentication will delegate to the ssh-agent");
       }
-      String azureGroupName = this.azureComputeConstants.azureResourceGroup();
+      String azureGroupName = 
locationToResourceGroupName.apply(template.getLocation().getId());
 
       AzureTemplateOptions options = 
template.getOptions().as(AzureTemplateOptions.class);
       // create resource group for jclouds group if it does not already exist

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e6785463/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeProperties.java
----------------------------------------------------------------------
diff --git 
a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeProperties.java
 
b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeProperties.java
index 8f945d9..2a15e4b 100644
--- 
a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeProperties.java
+++ 
b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeProperties.java
@@ -34,8 +34,6 @@ public class AzureComputeProperties {
 
    public static final String TCP_RULE_REGEXP = 
"jclouds.azurecompute.arm.tcp.rule.regexp";
 
-   public static final String RESOURCE_GROUP_NAME = 
"jclouds.azurecompute.arm.operation.resourcegroup";
-
    public static final String IMAGE_PUBLISHERS = 
"jclouds.azurecompute.arm.publishers";
 
    public static final String DEFAULT_IMAGE_LOGIN = 
"jclouds.azurecompute.arm.defaultimagelogin";

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e6785463/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/RegionAndId.java
----------------------------------------------------------------------
diff --git 
a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/RegionAndId.java
 
b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/RegionAndId.java
new file mode 100644
index 0000000..233109a
--- /dev/null
+++ 
b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/RegionAndId.java
@@ -0,0 +1,50 @@
+/*
+ * 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();
+   
+   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-labs/blob/e6785463/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/CleanupResources.java
----------------------------------------------------------------------
diff --git 
a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/CleanupResources.java
 
b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/CleanupResources.java
index 39cc32c..78909c6 100644
--- 
a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/CleanupResources.java
+++ 
b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/CleanupResources.java
@@ -16,7 +16,6 @@
  */
 package org.jclouds.azurecompute.arm.functions;
 
-import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Predicates.notNull;
 import static com.google.common.collect.Iterables.filter;
 import static com.google.common.collect.Iterables.transform;
@@ -25,7 +24,6 @@ import static org.jclouds.util.Closeables2.closeQuietly;
 
 import java.net.URI;
 import java.util.List;
-import java.util.Map;
 
 import javax.annotation.Resource;
 import javax.inject.Inject;
@@ -33,10 +31,11 @@ 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.IdReference;
 import org.jclouds.azurecompute.arm.domain.IpConfiguration;
 import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard;
-import org.jclouds.azurecompute.arm.domain.ResourceGroup;
+import org.jclouds.azurecompute.arm.domain.RegionAndId;
 import org.jclouds.azurecompute.arm.domain.StorageServiceKeys;
 import org.jclouds.azurecompute.arm.domain.VirtualMachine;
 import org.jclouds.azurecompute.arm.util.BlobHelper;
@@ -46,10 +45,8 @@ 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.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
 
 @Singleton
 public class CleanupResources implements Function<String, Boolean> {
@@ -61,28 +58,29 @@ public class CleanupResources implements Function<String, 
Boolean> {
    protected final AzureComputeApi api;
    private final Predicate<URI> resourceDeleted;
    private final StorageProfileToStorageAccountName 
storageProfileToStorageAccountName;
+   private final LocationToResourceGroupName locationToResourceGroupName;
 
    @Inject
    CleanupResources(AzureComputeApi azureComputeApi, 
@Named(TIMEOUT_RESOURCE_DELETED) Predicate<URI> resourceDeleted,
-         StorageProfileToStorageAccountName 
storageProfileToStorageAccountName) {
+         StorageProfileToStorageAccountName storageProfileToStorageAccountName,
+         LocationToResourceGroupName locationToResourceGroupName) {
       this.api = azureComputeApi;
       this.resourceDeleted = resourceDeleted;
       this.storageProfileToStorageAccountName = 
storageProfileToStorageAccountName;
+      this.locationToResourceGroupName = locationToResourceGroupName;
    }
 
    @Override
    public Boolean apply(final String id) {
-      logger.debug(">> destroying %s ...", id);
-
-      Map<String, VirtualMachine> resourceGroupNamesAndVirtualMachines = 
getResourceGroupNamesAndVirtualMachines(id);
-      if (resourceGroupNamesAndVirtualMachines.isEmpty())
+      RegionAndId regionAndId = RegionAndId.fromSlashEncoded(id);
+      String group = locationToResourceGroupName.apply(regionAndId.region());
+      
+      VirtualMachine virtualMachine = 
api.getVirtualMachineApi(group).get(regionAndId.id());
+      if (virtualMachine == null) {
          return true;
+      }
 
-      String group = 
checkNotNull(resourceGroupNamesAndVirtualMachines.entrySet().iterator().next().getKey(),
-            "resourceGroup name must not be null");
-      VirtualMachine virtualMachine = 
checkNotNull(resourceGroupNamesAndVirtualMachines.get(group),
-            "virtualMachine must not be null");
-
+      logger.debug(">> destroying %s ...", id);
       boolean vmDeleted = deleteVirtualMachine(group, virtualMachine);
       
       // We don't delete the network here, as it is global to the resource
@@ -163,14 +161,4 @@ public class CleanupResources implements Function<String, 
Boolean> {
       return 
resourceDeleted.apply(api.getVirtualMachineApi(group).delete(virtualMachine.name()));
    }
 
-   private Map<String, VirtualMachine> 
getResourceGroupNamesAndVirtualMachines(String id) {
-      for (ResourceGroup resourceGroup : api.getResourceGroupApi().list()) {
-         String group = resourceGroup.name();
-         VirtualMachine virtualMachine = 
api.getVirtualMachineApi(group).get(id);
-         if (virtualMachine != null) {
-            return ImmutableMap.of(group, virtualMachine);
-         }
-      }
-      return Maps.newHashMap();
-   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e6785463/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceLiveTest.java
----------------------------------------------------------------------
diff --git 
a/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceLiveTest.java
 
b/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceLiveTest.java
index c338954..a0ad66c 100644
--- 
a/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceLiveTest.java
+++ 
b/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceLiveTest.java
@@ -18,7 +18,7 @@ package org.jclouds.azurecompute.arm.compute;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static 
org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS;
-import static 
org.jclouds.azurecompute.arm.config.AzureComputeProperties.RESOURCE_GROUP_NAME;
+import static 
org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_PREFIX;
 import static 
org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING;
 import static 
org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED;
 import static 
org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED;
@@ -84,7 +84,7 @@ public class AzureComputeServiceLiveTest extends 
BaseComputeServiceLiveTest {
       properties.setProperty(TIMEOUT_PORT_OPEN, defaultTimeout);
       properties.setProperty(TIMEOUT_NODE_TERMINATED, defaultTimeout);
       properties.setProperty(TIMEOUT_NODE_SUSPENDED, defaultTimeout);
-      properties.put(RESOURCE_GROUP_NAME, "jc");
+      properties.put(RESOURCENAME_PREFIX, "jc");
       properties.put(PROPERTY_REGIONS, "eastus");
       properties.put(IMAGE_PUBLISHERS, "Canonical");
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e6785463/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureTemplateBuilderLiveTest.java
----------------------------------------------------------------------
diff --git 
a/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureTemplateBuilderLiveTest.java
 
b/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureTemplateBuilderLiveTest.java
index c20655b..794bde2 100644
--- 
a/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureTemplateBuilderLiveTest.java
+++ 
b/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureTemplateBuilderLiveTest.java
@@ -17,7 +17,7 @@
 package org.jclouds.azurecompute.arm.compute;
 
 import static com.google.common.base.Preconditions.checkNotNull;
-import static 
org.jclouds.azurecompute.arm.config.AzureComputeProperties.RESOURCE_GROUP_NAME;
+import static 
org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_PREFIX;
 import static org.jclouds.compute.util.ComputeServiceUtils.getCores;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertTrue;
@@ -58,7 +58,7 @@ public class AzureTemplateBuilderLiveTest extends 
BaseTemplateBuilderLiveTest {
    @Override
    protected Properties setupProperties() {
       Properties properties = super.setupProperties();
-      properties.put(RESOURCE_GROUP_NAME, "jc");
+      properties.put(RESOURCENAME_PREFIX, "jc");
 
       AzureLiveTestUtils.defaultProperties(properties);
       checkNotNull(setIfTestSystemPropertyPresent(properties, 
"oauth.endpoint"), "test.oauth.endpoint");

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e6785463/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtensionLiveTest.java
----------------------------------------------------------------------
diff --git 
a/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtensionLiveTest.java
 
b/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtensionLiveTest.java
index de44668..4d1a094 100644
--- 
a/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtensionLiveTest.java
+++ 
b/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtensionLiveTest.java
@@ -18,7 +18,7 @@ package org.jclouds.azurecompute.arm.compute.extensions;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static 
org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS;
-import static 
org.jclouds.azurecompute.arm.config.AzureComputeProperties.RESOURCE_GROUP_NAME;
+import static 
org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_PREFIX;
 import static 
org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING;
 import static 
org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED;
 import static 
org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED;
@@ -69,7 +69,7 @@ public class AzureComputeImageExtensionLiveTest extends 
BaseImageExtensionLiveTe
       properties.setProperty(TIMEOUT_PORT_OPEN, defaultTimeout);
       properties.setProperty(TIMEOUT_NODE_TERMINATED, defaultTimeout);
       properties.setProperty(TIMEOUT_NODE_SUSPENDED, defaultTimeout);
-      properties.put(RESOURCE_GROUP_NAME, "jc");
+      properties.put(RESOURCENAME_PREFIX, "jc");
       properties.put(PROPERTY_REGIONS, "eastus");
       properties.put(IMAGE_PUBLISHERS, "Canonical");
 

Reply via email to