Repository: jclouds-labs
Updated Branches:
  refs/heads/fix/AzureTemplateBuilderLiveTest 84ed11fce -> e450fd464


some more fixes


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

Branch: refs/heads/fix/AzureTemplateBuilderLiveTest
Commit: e450fd464792e53f2a5077262329c4214bdff1ba
Parents: 84ed11f
Author: Andrea Turli <[email protected]>
Authored: Tue Oct 4 14:56:29 2016 +0200
Committer: Andrea Turli <[email protected]>
Committed: Tue Oct 4 14:56:29 2016 +0200

----------------------------------------------------------------------
 .../arm/compute/AzureComputeServiceAdapter.java | 116 ++++++++-----------
 .../AzureComputeServiceContextModule.java       |  51 +++-----
 .../compute/options/AzureTemplateOptions.java   |  54 ++++++---
 .../CreateResourceGroupThenCreateNodes.java     |  75 +++++++++++-
 .../arm/config/AzureComputeProperties.java      |   4 +-
 .../arm/features/VirtualMachineApi.java         |   9 +-
 .../compute/AzureComputeServiceLiveTest.java    |   2 +-
 7 files changed, 182 insertions(+), 129 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e450fd46/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 c990f6c..0b7072a 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
@@ -16,7 +16,6 @@
  */
 package org.jclouds.azurecompute.arm.compute;
 
-import java.net.URI;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
@@ -60,10 +59,9 @@ import 
org.jclouds.azurecompute.arm.domain.VirtualMachineProperties;
 import org.jclouds.azurecompute.arm.features.OSImageApi;
 import org.jclouds.azurecompute.arm.features.PublicIPAddressApi;
 import org.jclouds.azurecompute.arm.functions.CleanupResources;
-import org.jclouds.azurecompute.arm.functions.ParseJobStatus;
 import org.jclouds.azurecompute.arm.util.BlobHelper;
-import org.jclouds.azurecompute.arm.util.DeploymentTemplateBuilder;
 import org.jclouds.compute.ComputeServiceAdapter;
+import org.jclouds.compute.domain.Image;
 import org.jclouds.compute.domain.Template;
 import org.jclouds.compute.reference.ComputeServiceConstants;
 import org.jclouds.location.Region;
@@ -73,7 +71,6 @@ import com.google.common.base.Function;
 import com.google.common.base.Objects;
 import com.google.common.base.Predicate;
 import com.google.common.base.Splitter;
-import com.google.common.base.Strings;
 import com.google.common.base.Supplier;
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.FluentIterable;
@@ -85,7 +82,6 @@ import com.google.common.collect.Multimap;
 import com.google.common.collect.Sets;
 
 import static com.google.common.base.Preconditions.checkState;
-import static 
org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageExtension.CUSTOM_IMAGE_PREFIX;
 import static 
org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING;
 import static org.jclouds.util.Predicates2.retry;
 
@@ -131,17 +127,48 @@ public class AzureComputeServiceAdapter implements 
ComputeServiceAdapter<Virtual
 
       // TODO ARM specific options
       
-      String adminUsername = 
Objects.firstNonNull(templateOptions.getLoginUser(), "jclouds");
-      OSProfile.LinuxConfiguration linuxConfiguration = 
OSProfile.LinuxConfiguration.create("true",
-              OSProfile.LinuxConfiguration.SSH.create(Arrays.asList(
-                      OSProfile.LinuxConfiguration.SSH.SSHPublicKey.create(
-                              String.format("/home/%s/.ssh/authorized_keys", 
adminUsername),
-                              templateOptions.getPublicKey())
-              ))
-      );
-
       String locationName = template.getLocation().getId();
+      String subnetId = templateOptions.getSubnetId();
+      NetworkInterfaceCard nic = createNetworkInterfaceCard(subnetId, name, 
locationName); 
+      StorageProfile storageProfile = createStorageProfile(name, 
template.getImage(), templateOptions.getBlob());
+      HardwareProfile hardwareProfile = 
HardwareProfile.builder().vmSize(template.getHardware().getId()).build();
+      OSProfile osProfile = createOsProfile(name, 
templateOptions.getLoginUser(), templateOptions.getPublicKey());
+      NetworkProfile networkProfile = 
NetworkProfile.builder().networkInterfaces(ImmutableList.of(IdReference.create(nic.id()))).build();
+      VirtualMachineProperties virtualMachineProperties = 
VirtualMachineProperties.builder()
+              .licenseType(null) // TODO
+              .availabilitySet(null) // TODO
+              .hardwareProfile(hardwareProfile)
+              .storageProfile(storageProfile)
+              .osProfile(osProfile)
+              .networkProfile(networkProfile)
+              .build();
+
+      VirtualMachine virtualMachine = 
api.getVirtualMachineApi(azureGroup).create(name, 
template.getLocation().getId(), virtualMachineProperties);
+
+      //Poll until resource is ready to be used
+      nodeRunningPredicate.apply(virtualMachine.name());
 
+      // Safe to pass null credentials here, as jclouds will default populate 
the node with the default credentials from the image, or the ones in the 
options, if provided.
+      return new NodeAndInitialCredentials<VirtualMachine>(virtualMachine, 
name, null);
+   }
+
+   private OSProfile createOsProfile(String computerName, String loginUser, 
String publicKey) {
+      String adminUsername = Objects.firstNonNull(loginUser, "jclouds");
+      OSProfile.Builder builder = 
OSProfile.builder().adminUsername(adminUsername).computerName(computerName);
+      if (publicKey !=null) {
+         OSProfile.LinuxConfiguration linuxConfiguration = 
OSProfile.LinuxConfiguration.create("true",
+                 OSProfile.LinuxConfiguration.SSH.create(Arrays.asList(
+                         OSProfile.LinuxConfiguration.SSH.SSHPublicKey.create(
+                                 
String.format("/home/%s/.ssh/authorized_keys", adminUsername),
+                                 publicKey)
+                 ))
+         );
+         builder.linuxConfiguration(linuxConfiguration);
+      }
+      return builder.build();
+   }
+
+   private NetworkInterfaceCard createNetworkInterfaceCard(String subnetId, 
String name, String locationName) {
       final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(azureGroup);
 
       PublicIPAddressProperties properties =
@@ -157,8 +184,7 @@ public class AzureComputeServiceAdapter implements 
ComputeServiceAdapter<Virtual
             return 
api.getPublicIPAddressApi(azureGroup).get(name).properties().provisioningState().equals("Succeeded");
          }
       }, 10 * 1000).apply(publicIpAddressName);
-      
-      String subnetId = templateOptions.getSubnetId();
+
       final NetworkInterfaceCardProperties networkInterfaceCardProperties =
               NetworkInterfaceCardProperties.builder()
                       .ipConfigurations(ImmutableList.of(
@@ -173,63 +199,19 @@ public class AzureComputeServiceAdapter implements 
ComputeServiceAdapter<Virtual
                       .build();
 
       String networkInterfaceCardName = "jc-nic-" + name;
-      NetworkInterfaceCard nic = 
api.getNetworkInterfaceCardApi(azureGroup).createOrUpdate(networkInterfaceCardName,
 locationName, networkInterfaceCardProperties, ImmutableMap.of("jclouds", 
"livetest"));
-      
-      // TODO move storageAccount to CreateResourceGroupThenCreateNodes
-      String storageAccountName = null;
-      String imageName = template.getImage().getName();
-      if (imageName.startsWith(CUSTOM_IMAGE_PREFIX)) {
-         storageAccountName = template.getImage().getVersion();
-      }
-
-      if (Strings.isNullOrEmpty(storageAccountName)) {
-         storageAccountName = 
DeploymentTemplateBuilder.generateStorageAccountName(name);
-      }
-
-      URI uri = 
api.getStorageAccountApi(azureGroup).create(storageAccountName, locationName, 
ImmutableMap.of("property_name",
-              "property_value"), ImmutableMap.of("accountType", 
StorageService.AccountType.Standard_LRS.toString()));
-         retry(new Predicate<URI>() {
-            @Override
-            public boolean apply(URI uri) {
-               return ParseJobStatus.JobStatus.DONE == 
api.getJobApi().jobStatus(uri);
-            }
-         }, 60 * 1 * 1000 /* 1 minute timeout */).apply(uri);
-      StorageService storageService = 
api.getStorageAccountApi(azureGroup).get(storageAccountName);
-      String blob = 
storageService.storageServiceProperties().primaryEndpoints().get("blob");
+      return 
api.getNetworkInterfaceCardApi(azureGroup).createOrUpdate(networkInterfaceCardName,
 locationName, networkInterfaceCardProperties, ImmutableMap.of("jclouds", 
"livetest"));
+   }
 
+   private StorageProfile createStorageProfile(String name, Image image, 
String blob) {
       ImageReference imageReference = ImageReference.builder()
-              .publisher(template.getImage().getProviderId())
-              .offer(template.getImage().getName())
-              .sku(template.getImage().getVersion())
+              .publisher(image.getProviderId())
+              .offer(image.getName())
+              .sku(image.getVersion())
               .version("latest")
               .build();
       VHD vhd = VHD.create(blob + "vhds/" + name + ".vhd");
       OSDisk osDisk = OSDisk.create(null, name, vhd, "ReadWrite", "FromImage", 
null);
-      StorageProfile storageProfile = StorageProfile.create(imageReference, 
osDisk, ImmutableList.<DataDisk>of());
-
-      VirtualMachineProperties virtualMachineProperties = 
VirtualMachineProperties.builder()
-              .licenseType(null) // TODO
-              .availabilitySet(null)
-              
.hardwareProfile(HardwareProfile.builder().vmSize(template.getHardware().getId()).build())
-              .storageProfile(storageProfile)
-              .osProfile(OSProfile.builder()
-                      .adminUsername(adminUsername)
-                      .linuxConfiguration(linuxConfiguration)
-                      .computerName(name)
-                      .build())
-              .networkProfile(NetworkProfile.builder()
-                      
.networkInterfaces(ImmutableList.of(IdReference.create(nic.id())))
-                      .build())
-              .build();
-
-      VirtualMachine virtualMachine = 
api.getVirtualMachineApi(azureGroup).create(name, 
template.getLocation().getId(), virtualMachineProperties);
-
-      //Poll until resource is ready to be used
-      nodeRunningPredicate.apply(virtualMachine.name());
-
-      // Safe to pass null credentials here, as jclouds will default populate 
the node with the default credentials from the image, or the ones in the 
options, if provided.
-      return new NodeAndInitialCredentials<VirtualMachine>(virtualMachine, 
name, null);
-   }
+      return StorageProfile.create(imageReference, osDisk, 
ImmutableList.<DataDisk>of());   }
 
    @Override
    public Iterable<VMHardware> listHardwareProfiles() {

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e450fd46/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 34319d0..896b880 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
@@ -38,7 +38,7 @@ import org.jclouds.azurecompute.arm.domain.ResourceDefinition;
 import org.jclouds.azurecompute.arm.domain.VMHardware;
 import org.jclouds.azurecompute.arm.domain.VMImage;
 import org.jclouds.azurecompute.arm.domain.VirtualMachine;
-import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance;
+import 
org.jclouds.azurecompute.arm.domain.VirtualMachineProperties.ProvisioningState;
 import org.jclouds.azurecompute.arm.functions.ParseJobStatus;
 import org.jclouds.compute.ComputeService;
 import org.jclouds.compute.ComputeServiceAdapter;
@@ -197,8 +197,9 @@ public class AzureComputeServiceContextModule
 
    @Provides
    @com.google.inject.name.Named(TIMEOUT_NODE_RUNNING)
-   protected Predicate<String> provideVirtualMachineRunningPredicate(final 
AzureComputeApi api, String resourceGroupName, Timeouts timeouts, PollPeriod 
pollPeriod) {
-      return retry(new VirtualMachineInStatePredicate(api, resourceGroupName, 
VirtualMachineInstance.VirtualMachineStatus.create("PowerState/running", 
"Info", "VM running", null)), timeouts.nodeRunning,
+   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, 
ProvisioningState.SUCCEEDED), timeouts.nodeRunning,
               pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod);
    }
    
@@ -228,7 +229,8 @@ public class AzureComputeServiceContextModule
    protected Predicate<String> provideNodeSuspendedPredicate(final 
AzureComputeApi api, final 
AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants,
                                                              Timeouts 
timeouts, PollPeriod pollPeriod) {
       String azureGroup = azureComputeConstants.azureResourceGroup();
-      return retry(new NodeSuspendedPredicate(api, azureGroup), 
timeouts.nodeSuspended, pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod);
+      return retry(new VirtualMachineInStatePredicate(api, azureGroup, 
ProvisioningState.DELETED), timeouts.nodeTerminated,
+              pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod);
    }
 
    @VisibleForTesting
@@ -271,49 +273,22 @@ public class AzureComputeServiceContextModule
 
       private final AzureComputeApi api;
       private final String azureGroup;
-      private final VirtualMachineInstance.VirtualMachineStatus status;
+      private final ProvisioningState provisioningState;
 
-      public VirtualMachineInStatePredicate(AzureComputeApi api, String 
azureGroup, VirtualMachineInstance.VirtualMachineStatus status) {
+      public VirtualMachineInStatePredicate(AzureComputeApi api, String 
azureGroup, ProvisioningState provisioningState) {
          this.api = checkNotNull(api, "api must not be null");
          this.azureGroup = checkNotNull(azureGroup, "azuregroup must not be 
null");
-         this.status = status;
+         this.provisioningState = provisioningState;
       }
 
       @Override
       public boolean apply(String name) {
          checkNotNull(name, "name cannot be null");
-         VirtualMachineInstance virtualMachineInstance = 
api.getVirtualMachineApi(this.azureGroup).getInstanceDetails(name);
-         if (virtualMachineInstance == null) return false;
-         List<VirtualMachineInstance.VirtualMachineStatus> statuses = 
virtualMachineInstance.statuses();
-         return status.equals("VM stopped");
+         VirtualMachine virtualMachine = 
api.getVirtualMachineApi(this.azureGroup).get(name);
+         if (virtualMachine == null) return false;
+         ProvisioningState state = 
virtualMachine.properties().provisioningState();
+         return state == provisioningState;
       }
    }
 
-   @VisibleForTesting
-   static class NodeSuspendedPredicate implements Predicate<String> {
-
-      private final AzureComputeApi api;
-      private final String azureGroup;
-
-      public NodeSuspendedPredicate(AzureComputeApi api, String azureGroup) {
-         this.api = checkNotNull(api, "api must not be null");
-         this.azureGroup = checkNotNull(azureGroup, "azuregroup must not be 
null");
-      }
-
-      @Override
-      public boolean apply(String name) {
-         checkNotNull(name, "name cannot be null");
-         String status = "";
-         VirtualMachineInstance virtualMachineInstance = 
api.getVirtualMachineApi(this.azureGroup).getInstanceDetails(name);
-         if (virtualMachineInstance == null) return false;
-         List<VirtualMachineInstance.VirtualMachineStatus> statuses = 
virtualMachineInstance.statuses();
-         for (int c = 0; c < statuses.size(); c++) {
-            if (statuses.get(c).code().substring(0, 10).equals("PowerState")) {
-               status = statuses.get(c).displayStatus();
-               break;
-            }
-         }
-         return status.equals("VM stopped");
-      }
-   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e450fd46/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/AzureTemplateOptions.java
----------------------------------------------------------------------
diff --git 
a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/AzureTemplateOptions.java
 
b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/AzureTemplateOptions.java
index c5267b1..c71a7da 100644
--- 
a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/AzureTemplateOptions.java
+++ 
b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/AzureTemplateOptions.java
@@ -16,10 +16,12 @@
  */
 package org.jclouds.azurecompute.arm.compute.options;
 
-import static com.google.common.base.Objects.equal;
 import org.jclouds.compute.options.TemplateOptions;
+
 import com.google.common.base.Objects;
 
+import static com.google.common.base.Objects.equal;
+
 /**
  * Azure ARM custom options
  */
@@ -31,7 +33,9 @@ public class AzureTemplateOptions extends TemplateOptions 
implements Cloneable {
    private String subnetAddressPrefix;
    private String DNSLabelPrefix;
    private String keyVaultIdAndSecret;
-
+   private String virtualNetworkName;
+   private String subnetId;
+   private String blob;
 
    /**
     * Custom options for the Azure ARM API
@@ -40,9 +44,7 @@ public class AzureTemplateOptions extends TemplateOptions 
implements Cloneable {
       this.customData = customData;
       return this;
    }
-   private String virtualNetworkName;
-   private String subnetId;
-
+   
    /**
     * Sets the CIDR block for virtual network
     */
@@ -75,15 +77,6 @@ public class AzureTemplateOptions extends TemplateOptions 
implements Cloneable {
       return this;
    }
 
-   public String getCustomData() { return customData; }
-   public String getVirtualNetworkAddressPrefix() { return 
virtualNetworkAddressPrefix; }
-   public String getSubnetAddressPrefix() { return subnetAddressPrefix; }
-   public String getDNSLabelPrefix() { return DNSLabelPrefix; }
-   public String getKeyVaultIdAndSecret() { return keyVaultIdAndSecret; }
-   public String getVirtualNetworkName() { return virtualNetworkName; }
-   public String getSubnetId() { return subnetId; }
-
-
    /**
     * Sets the virtual network name
     */
@@ -100,6 +93,24 @@ public class AzureTemplateOptions extends TemplateOptions 
implements Cloneable {
       return this;
    }
 
+   /**
+    * Sets the blob name
+    */
+   public  AzureTemplateOptions blob(String blob) {
+      this.blob = blob;
+      return this;
+   }
+
+   public String getCustomData() { return customData; }
+   public String getVirtualNetworkAddressPrefix() { return 
virtualNetworkAddressPrefix; }
+   public String getSubnetAddressPrefix() { return subnetAddressPrefix; }
+   public String getDNSLabelPrefix() { return DNSLabelPrefix; }
+   public String getKeyVaultIdAndSecret() { return keyVaultIdAndSecret; }
+   public String getVirtualNetworkName() { return virtualNetworkName; }
+   public String getSubnetId() { return subnetId; }
+   public String getBlob() { return blob; }
+
+
    @Override
    public AzureTemplateOptions clone() {
       AzureTemplateOptions options = new AzureTemplateOptions();
@@ -119,12 +130,13 @@ public class AzureTemplateOptions extends TemplateOptions 
implements Cloneable {
          eTo.keyVaultIdAndSecret(keyVaultIdAndSecret);
          eTo.virtualNetworkName(virtualNetworkName);
          eTo.subnetId(subnetId);
+         eTo.blob(blob);
       }
    }
 
    @Override
    public int hashCode() {
-      return Objects.hashCode(super.hashCode(), virtualNetworkAddressPrefix, 
subnetAddressPrefix, DNSLabelPrefix, customData, keyVaultIdAndSecret, 
virtualNetworkName, subnetId);
+      return Objects.hashCode(super.hashCode(), virtualNetworkAddressPrefix, 
subnetAddressPrefix, DNSLabelPrefix, customData, keyVaultIdAndSecret, 
virtualNetworkName, subnetId, blob);
    }
 
    @Override
@@ -146,7 +158,8 @@ public class AzureTemplateOptions extends TemplateOptions 
implements Cloneable {
             && equal(this.DNSLabelPrefix, other.DNSLabelPrefix)
             && equal(this.keyVaultIdAndSecret, other.keyVaultIdAndSecret)
             && equal(this.virtualNetworkName, other.virtualNetworkName)
-            && equal(this.subnetId, other.subnetId);
+            && equal(this.subnetId, other.subnetId)
+            && equal(this.blob, other.blob);
    }
 
    @Override
@@ -159,6 +172,7 @@ public class AzureTemplateOptions extends TemplateOptions 
implements Cloneable {
       toString.add("keyVaultIdAndSecret", keyVaultIdAndSecret);
       toString.add("virtualNetworkName", virtualNetworkName);
       toString.add("subnetId", subnetId);
+      toString.add("blob", blob);
       return toString;
    }
 
@@ -219,5 +233,13 @@ public class AzureTemplateOptions extends TemplateOptions 
implements Cloneable {
          AzureTemplateOptions options = new AzureTemplateOptions();
          return options.subnetId(subnetId);
       }
+
+      /**
+       * @see AzureTemplateOptions#blob
+       */
+      public static AzureTemplateOptions blob(String blob) {
+         AzureTemplateOptions options = new AzureTemplateOptions();
+         return options.blob(blob);
+      }
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e450fd46/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 59375b5..a7900ec 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
@@ -16,9 +16,11 @@
  */
 package org.jclouds.azurecompute.arm.compute.strategy;
 
+import java.net.URI;
 import java.util.Arrays;
 import java.util.Map;
 import java.util.Set;
+import java.util.UUID;
 
 import javax.annotation.Resource;
 import javax.inject.Inject;
@@ -30,12 +32,15 @@ import org.jclouds.azurecompute.arm.AzureComputeApi;
 import 
org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule;
 import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions;
 import org.jclouds.azurecompute.arm.domain.ResourceGroup;
+import org.jclouds.azurecompute.arm.domain.StorageService;
 import org.jclouds.azurecompute.arm.domain.Subnet;
 import org.jclouds.azurecompute.arm.domain.VirtualNetwork;
 import org.jclouds.azurecompute.arm.features.ResourceGroupApi;
 import org.jclouds.azurecompute.arm.features.SubnetApi;
 import org.jclouds.azurecompute.arm.features.VirtualNetworkApi;
+import org.jclouds.azurecompute.arm.functions.ParseJobStatus;
 import org.jclouds.compute.config.CustomizationResponse;
+import org.jclouds.compute.domain.Image;
 import org.jclouds.compute.domain.NodeMetadata;
 import org.jclouds.compute.domain.Template;
 import org.jclouds.compute.functions.GroupNamingConvention;
@@ -46,12 +51,16 @@ import org.jclouds.compute.strategy.ListNodesStrategy;
 import 
org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet;
 import org.jclouds.logging.Logger;
 
+import com.google.common.base.Predicate;
+import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Multimap;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static 
org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageExtension.CUSTOM_IMAGE_PREFIX;
+import static org.jclouds.util.Predicates2.retry;
 
 @Singleton
 public class CreateResourceGroupThenCreateNodes extends 
CreateNodesWithGroupEncodedIntoNameThenAddToSet {
@@ -111,7 +120,10 @@ public class CreateResourceGroupThenCreateNodes extends 
CreateNodesWithGroupEnco
 
       this.getOrCreateVirtualNetworkWithSubnet(vnetName, subnetName, location, 
options, azureGroupName);
 
-
+      StorageService storageService = getOrCreateStorageService(group, 
azureGroupName, location, template.getImage());
+      String blob = 
storageService.storageServiceProperties().primaryEndpoints().get("blob");
+      options.blob(blob);
+      
       Map<?, ListenableFuture<Void>> responses = super.execute(group, count, 
template, goodNodes, badNodes,
               customizationResponses);
 
@@ -148,5 +160,64 @@ public class CreateResourceGroupThenCreateNodes extends 
CreateNodesWithGroupEnco
       return template.getOptions().getRunScript() != null && 
template.getOptions().getPublicKey() != null
               && !template.getOptions().hasLoginPrivateKeyOption();
    }
-   
+
+   public StorageService getOrCreateStorageService(String name, String 
resourceGroupName, String locationName, Image image) {
+      String storageAccountName = null;
+      String imageName = image.getName();
+      if (imageName.startsWith(CUSTOM_IMAGE_PREFIX)) {
+         storageAccountName = image.getVersion();
+      }
+
+      if (Strings.isNullOrEmpty(storageAccountName)) {
+         storageAccountName = generateStorageAccountName(name);
+      }
+
+      StorageService storageService = 
api.getStorageAccountApi(resourceGroupName).get(storageAccountName);
+      if (storageService != null) return storageService;
+
+      URI uri = 
api.getStorageAccountApi(resourceGroupName).create(storageAccountName, 
locationName, ImmutableMap.of("property_name",
+              "property_value"), ImmutableMap.of("accountType", 
StorageService.AccountType.Standard_LRS.toString()));
+      retry(new Predicate<URI>() {
+         @Override
+         public boolean apply(URI uri) {
+            return ParseJobStatus.JobStatus.DONE == 
api.getJobApi().jobStatus(uri);
+         }
+      }, 60 * 1 * 1000 /* 1 minute timeout */).apply(uri);
+      storageService = 
api.getStorageAccountApi(resourceGroupName).get(storageAccountName);
+      return storageService;
+   }
+
+   /**
+    * Generates a valid storage account
+    *
+    * Storage account names must be between 3 and 24 characters in length and 
may contain numbers and lowercase letters only.
+    *
+    * @param name the node name
+    * @return the storage account name starting from a sanitized name (with 
only numbers and lowercase letters only ).
+    * If sanitized name is between 3 and 24 characters, storage account name 
is equals to sanitized name.
+    * If sanitized name is less than 3 characters, storage account is 
sanitized name plus 4 random chars.
+    * If sanitized name is more than 24 characters, storage account is first 
10 chars of sanitized name plus 4 random chars plus last 10 chars of sanitized 
name.
+    */
+   public static String generateStorageAccountName(String name) {
+      String storageAccountName = name.replaceAll("[^a-z0-9]", "");
+      int nameLength = storageAccountName.length();
+      if (nameLength >= 3 && nameLength <= 24) {
+         return storageAccountName;
+      }
+
+      String random = UUID.randomUUID().toString().replaceAll("[^a-z0-9]", 
"").substring(0, 4);
+      if (nameLength < 3) {
+         storageAccountName = new 
StringBuilder().append(storageAccountName).append(random).toString();
+      }
+      if (nameLength > 24) {
+         storageAccountName = shorten(storageAccountName, random);
+      }
+      return storageAccountName;
+   }
+
+   private static String shorten(String storageAccountName, String random) {
+      String prefix = storageAccountName.substring(0, 10);
+      String suffix = storageAccountName.substring(storageAccountName.length() 
- 10, storageAccountName.length());
+      return String.format("%s%s%s", prefix, random, suffix);
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e450fd46/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 e5ef5cd..968ba3f 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
@@ -21,6 +21,8 @@ package org.jclouds.azurecompute.arm.config;
  */
 public class AzureComputeProperties {
 
+   public static final String STORAGE_API_VERSION = "2015-06-15";
+
    public static final String OPERATION_TIMEOUT = 
"jclouds.azurecompute.arm.operation.timeout";
 
    public static final String OPERATION_POLL_INITIAL_PERIOD = 
"jclouds.azurecompute.arm.operation.poll.initial.period";
@@ -31,8 +33,6 @@ public class AzureComputeProperties {
 
    public static final String TCP_RULE_REGEXP = 
"jclouds.azurecompute.arm.tcp.rule.regexp";
 
-   public static final String STORAGE_API_VERSION = "2015-06-15";
-
    public static final String RESOURCE_GROUP_NAME = 
"jclouds.azurecompute.arm.operation.resourcegroup";
 
    public static final String IMAGE_PUBLISHERS = 
"jclouds.azurecompute.arm.publishers";

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e450fd46/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualMachineApi.java
----------------------------------------------------------------------
diff --git 
a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualMachineApi.java
 
b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualMachineApi.java
index 0b62ca7..e0c7e27 100644
--- 
a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualMachineApi.java
+++ 
b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualMachineApi.java
@@ -53,7 +53,6 @@ import org.jclouds.rest.binders.BindToJsonPayload;
  */
 
@Path("/resourceGroups/{resourceGroup}/providers/Microsoft.Compute/virtualMachines")
 @RequestFilters(OAuthFilter.class)
-@QueryParams(keys = "api-version", values = "2015-06-15")
 @Consumes(MediaType.APPLICATION_JSON)
 public interface VirtualMachineApi {
 
@@ -63,6 +62,7 @@ public interface VirtualMachineApi {
    @Named("GetVirtualMachine")
    @GET
    @Path("/{name}")
+   @QueryParams(keys = "api-version", values = "2016-03-30")
    @Fallback(Fallbacks.NullOnNotFoundOr404.class)
    VirtualMachine get(@PathParam("name") String name);
 
@@ -72,9 +72,10 @@ public interface VirtualMachineApi {
    @Named("GetVirtualMachineInstance")
    @GET
    @Path("/{name}/instanceView")
+   @QueryParams(keys = "api-version", values = "2016-03-30")
    @Fallback(Fallbacks.NullOnNotFoundOr404.class)
    VirtualMachineInstance getInstanceDetails(@PathParam("name") String name);
-
+   
    /**
     * The Create Virtual Machine
     */
@@ -83,7 +84,7 @@ public interface VirtualMachineApi {
    
@Payload("%7B\"location\":\"{location}\",\"tags\":%7B%7D,\"properties\":{properties}%7D")
    @MapBinder(BindToJsonPayload.class)
    @Path("/{vmname}")
-   @QueryParams(keys = "validating", values = "false")
+   @QueryParams(keys = { "validating", "api-version"}, values = {"false", 
"2016-03-30"})
    @Produces(MediaType.APPLICATION_JSON)
    VirtualMachine create(@PathParam("vmname") String vmname,
                          @PayloadParam("location") String location,
@@ -96,6 +97,7 @@ public interface VirtualMachineApi {
    @GET
    @SelectJson("value")
    @Fallback(Fallbacks.EmptyListOnNotFoundOr404.class)
+   @QueryParams(keys = "api-version", values = "2016-06-01" )
    List<VirtualMachine> list();
 
    /**
@@ -105,6 +107,7 @@ public interface VirtualMachineApi {
    @DELETE
    @Path("/{name}")
    @ResponseParser(URIParser.class)
+   @QueryParams(keys = "api-version", values = "2016-03-30")
    @Fallback(Fallbacks.NullOnNotFoundOr404.class)
    URI delete(@PathParam("name") String name);
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e450fd46/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 6629360..eaa9ac2 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
@@ -105,7 +105,7 @@ public class AzureComputeServiceLiveTest extends 
BaseComputeServiceLiveTest {
 
    @Override
    protected Template buildTemplate(TemplateBuilder templateBuilder) {
-      Template template = templateBuilder.build();
+      Template template = 
templateBuilder.imageVersionMatches("16.04.0-LTS").build();
       AzureTemplateOptions options = 
template.getOptions().as(AzureTemplateOptions.class);
       options.authorizePublicKey("ssh-rsa 
AAAAB3NzaC1yc2EAAAADAQABAAABAQDNnvPZ25wZK19grrbal6R5JP1hLRBUuNh86KxZVMAFkGd5ouVSgO9dFajHZ45Q4mbaTkdOiqf7otMLDzkaztEa7oLK7Jso0Y0LOi+nT4gf38rvbEF5mq069G9b9XqlNleaGnpLuTN54iEK8c4TWZxIJqgelHEHhjp7V1asmilBbpZDmwA5cTt9vGJIhqA/BptKH3folZKeAQjRa1ZRSwSQUnk9rBKn4PKSRDojVa9A9jKt4qboJh5q7ZjtE8z+665F/4TgLzElTXUA8+uUFGpuynMSmQEt301e18dXAl+vBr8fMiThcoVVbdVdqdjXsw75fMXPAgqhjrw8k3+0/4P9
 [email protected]");
       return template;

Reply via email to