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;
