Repository: jclouds-labs Updated Branches: refs/heads/fix/AzureTemplateBuilderLiveTest d9600c00f -> 226633157
Fixed Azure ARM Image extension Project: http://git-wip-us.apache.org/repos/asf/jclouds-labs/repo Commit: http://git-wip-us.apache.org/repos/asf/jclouds-labs/commit/22663315 Tree: http://git-wip-us.apache.org/repos/asf/jclouds-labs/tree/22663315 Diff: http://git-wip-us.apache.org/repos/asf/jclouds-labs/diff/22663315 Branch: refs/heads/fix/AzureTemplateBuilderLiveTest Commit: 226633157222d11d6a708fedd5581e61de8672df Parents: d9600c0 Author: Ignasi Barrera <n...@apache.org> Authored: Wed Oct 12 20:33:53 2016 +0200 Committer: Ignasi Barrera <n...@apache.org> Committed: Wed Oct 12 20:34:51 2016 +0200 ---------------------------------------------------------------------- .../arm/AzureComputeProviderMetadata.java | 2 +- .../arm/compute/AzureComputeServiceAdapter.java | 110 ++++++------ .../AzureComputeServiceContextModule.java | 71 ++++---- .../extensions/AzureComputeImageExtension.java | 177 +++++++++---------- .../ResourceDefinitionToCustomImage.java | 76 ++++++++ .../arm/compute/functions/VMImageToImage.java | 25 +-- .../functions/VirtualMachineToNodeMetadata.java | 50 ++++-- .../CreateResourceGroupThenCreateNodes.java | 23 +-- .../azurecompute/arm/domain/VMImage.java | 43 +++-- .../arm/functions/CleanupResources.java | 157 +++++++--------- .../azurecompute/arm/util/BlobHelper.java | 72 ++++---- .../compute/AzureComputeServiceLiveTest.java | 13 +- .../AzureComputeImageExtensionLiveTest.java | 56 +++--- 13 files changed, 483 insertions(+), 392 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/22663315/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 86f1420..a434079 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 @@ -88,7 +88,7 @@ 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, "jcloudsgroup"); + 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(DEFAULT_DATADISKSIZE, "100"); http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/22663315/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 d21bd43..d6d9267 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 @@ -19,21 +19,21 @@ package org.jclouds.azurecompute.arm.compute; import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.Iterables.contains; import static com.google.common.collect.Iterables.filter; -import static org.jclouds.compute.config.ComputeServiceProperties.IMAGE_LOGIN_USER; -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING; +import static com.google.common.collect.Iterables.find; +import static org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageExtension.CONTAINER_NAME; +import static org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageExtension.CUSTOM_IMAGE_OFFER; +import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.decodeFieldsFromUniqueId; +import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.encodeFieldsToUniqueIdCustom; import java.util.List; import java.util.Set; -import javax.annotation.Resource; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.azurecompute.arm.AzureComputeApi; -import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.AzureComputeConstants; -import org.jclouds.azurecompute.arm.compute.functions.VMImageToImage; import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; import org.jclouds.azurecompute.arm.domain.DataDisk; import org.jclouds.azurecompute.arm.domain.HardwareProfile; @@ -54,6 +54,7 @@ import org.jclouds.azurecompute.arm.domain.ResourceProviderMetaData; import org.jclouds.azurecompute.arm.domain.SKU; import org.jclouds.azurecompute.arm.domain.StorageProfile; import org.jclouds.azurecompute.arm.domain.StorageService; +import org.jclouds.azurecompute.arm.domain.StorageService.Status; import org.jclouds.azurecompute.arm.domain.VHD; import org.jclouds.azurecompute.arm.domain.VMHardware; import org.jclouds.azurecompute.arm.domain.VMImage; @@ -67,10 +68,9 @@ import org.jclouds.azurecompute.arm.functions.CleanupResources; import org.jclouds.azurecompute.arm.util.BlobHelper; import org.jclouds.compute.ComputeServiceAdapter; import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.Template; -import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.location.Region; -import org.jclouds.logging.Logger; import com.google.common.base.Function; import com.google.common.base.Objects; @@ -90,32 +90,22 @@ import com.google.common.collect.Lists; @Singleton public class AzureComputeServiceAdapter implements ComputeServiceAdapter<VirtualMachine, VMHardware, VMImage, Location> { - @Resource - @Named(ComputeServiceConstants.COMPUTE_LOGGER) - private Logger logger = Logger.NULL; - 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> nodeRunningPredicate; private final Predicate<String> publicIpAvailable; @Inject AzureComputeServiceAdapter(final AzureComputeApi api, final AzureComputeConstants azureComputeConstants, CleanupResources cleanupResources, @Region Supplier<Set<String>> regionIds, - @Named(TIMEOUT_NODE_RUNNING) Predicate<String> nodeRunningPredicate, @Named("PublicIpAvailable") Predicate<String> publicIpAvailable) { this.api = api; this.azureComputeConstants = azureComputeConstants; this.azureGroup = azureComputeConstants.azureResourceGroup(); - - logger.debug("AzureComputeServiceAdapter set azuregroup to: " + azureGroup); - this.cleanupResources = cleanupResources; this.regionIds = regionIds; - this.nodeRunningPredicate = nodeRunningPredicate; this.publicIpAvailable = publicIpAvailable; } @@ -136,7 +126,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual 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); + OSProfile osProfile = createOsProfile(name, template); NetworkProfile networkProfile = NetworkProfile.builder().networkInterfaces(ImmutableList.of(IdReference.create(nic.id()))).build(); VirtualMachineProperties virtualMachineProperties = VirtualMachineProperties.builder() .licenseType(null) // TODO @@ -149,9 +139,6 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual 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); } @@ -188,7 +175,8 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual for (SKU sku : skuList) { Iterable<Version> versionList = osImageApi.listVersions(publisherName, offer.name(), sku.name()); for (Version version : versionList) { - VMImage vmImage = VMImage.create(publisherName, offer.name(), sku.name(), version.name(), location); + VMImage vmImage = VMImage.azureImage().publisher(publisherName).offer(offer.name()).sku(sku.name()) + .version(version.name()).location(location).build(); osImagesRef.add(vmImage); } } @@ -217,10 +205,10 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual for (StorageService storage : storages) { String name = storage.name(); StorageService storageService = api.getStorageAccountApi(azureGroup).get(name); - if (storageService != null && storageService.storageServiceProperties().provisioningState().equals("Succeded")) { + if (storageService != null && Status.Succeeded == storageService.storageServiceProperties().provisioningState()) { String key = api.getStorageAccountApi(azureGroup).getKeys(name).key1(); - List<VMImage> images = BlobHelper.getImages("jclouds", azureGroup, storage.name(), key, - "custom", storage.location()); + List<VMImage> images = BlobHelper.getImages(CONTAINER_NAME, azureGroup, storage.name(), key, + CUSTOM_IMAGE_OFFER, storage.location()); osImages.addAll(images); } } @@ -230,14 +218,21 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual @Override public VMImage getImage(final String id) { - VMImage image = VMImageToImage.decodeFieldsFromUniqueId(id); + VMImage image = decodeFieldsFromUniqueId(id); if (image.custom()) { + VMImage customImage = null; String key = api.getStorageAccountApi(azureGroup).getKeys(image.storage()).key1(); - if (BlobHelper.customImageExists(image.storage(), key)) - return image; - else - return null; - + if (BlobHelper.customImageExists(image.storage(), key)) { + List<VMImage> customImagesInStorage = BlobHelper.getImages(CONTAINER_NAME, azureGroup, image.storage(), key, + CUSTOM_IMAGE_OFFER, image.location()); + customImage = find(customImagesInStorage, new Predicate<VMImage>() { + @Override public boolean apply(VMImage input) { + return id.equals(encodeFieldsToUniqueIdCustom(input)); + } + }, null); + } + + return customImage; } String location = image.location(); @@ -248,7 +243,8 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual OSImageApi osImageApi = api.getOSImageApi(location); List<Version> versions = osImageApi.listVersions(publisher, offer, sku); if (!versions.isEmpty()) { - return VMImage.create(publisher, offer, sku, versions.get(0).name(), location); + return VMImage.azureImage().publisher(publisher).offer(offer).sku(sku).version(versions.get(0).name()) + .location(location).build(); } return null; } @@ -328,20 +324,19 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual } - private OSProfile createOsProfile(String computerName, AzureTemplateOptions templateOptions) { - Iterable<String> splittedImageLoginUser = Splitter.on(":").split(AzureComputeProviderMetadata.defaultProperties().getProperty(IMAGE_LOGIN_USER)); - String defaultLoginUser = Iterables.get(splittedImageLoginUser, 0); - String defaultLoginPassword = Iterables.get(splittedImageLoginUser, 1); - String adminUsername = Objects.firstNonNull(templateOptions.getLoginUser(), defaultLoginUser); - String adminPassword = Objects.firstNonNull(templateOptions.getLoginPassword(), defaultLoginPassword); + private OSProfile createOsProfile(String computerName, Template template) { + String defaultLoginUser = template.getImage().getDefaultCredentials().getUser(); + String defaultLoginPassword = template.getImage().getDefaultCredentials().getOptionalPassword().get(); + String adminUsername = Objects.firstNonNull(template.getOptions().getLoginUser(), defaultLoginUser); + String adminPassword = Objects.firstNonNull(template.getOptions().getLoginPassword(), defaultLoginPassword); OSProfile.Builder builder = OSProfile.builder().adminUsername(adminUsername).computerName(computerName); // prefer public key over password - if (templateOptions.getPublicKey() != null) { + if (template.getOptions().getPublicKey() != null) { OSProfile.LinuxConfiguration linuxConfiguration = OSProfile.LinuxConfiguration.create("true", OSProfile.LinuxConfiguration.SSH.create(ImmutableList.of( OSProfile.LinuxConfiguration.SSH.SSHPublicKey.create( String.format("/home/%s/.ssh/authorized_keys", adminUsername), - templateOptions.getPublicKey()) + template.getOptions().getPublicKey()) )) ); builder.linuxConfiguration(linuxConfiguration); @@ -362,10 +357,8 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual String publicIpAddressName = "public-address-" + name; PublicIPAddress ip = ipApi.createOrUpdate(publicIpAddressName, locationName, ImmutableMap.of("jclouds", name), properties); - publicIpAvailable.apply(publicIpAddressName); - // Refresh after last polling - ip = api.getPublicIPAddressApi(azureGroup).get(publicIpAddressName); - checkState(ip.properties().provisioningState().equals("Succeeded"), + + checkState(publicIpAvailable.apply(publicIpAddressName), "Public IP was not provisioned in the configured timeout"); final NetworkInterfaceCardProperties networkInterfaceCardProperties = @@ -386,14 +379,29 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual } private StorageProfile createStorageProfile(String name, Image image, String blob) { - ImageReference imageReference = ImageReference.builder() - .publisher(image.getProviderId()) - .offer(image.getName()) - .sku(image.getVersion()) - .version("latest") - .build(); + VMImage imageRef = decodeFieldsFromUniqueId(image.getId()); + ImageReference imageReference = null; + VHD sourceImage = null; + String osType = null; + + if (!imageRef.custom()) { + imageReference = ImageReference.builder() + .publisher(image.getProviderId()) + .offer(image.getName()) + .sku(image.getVersion()) + .version("latest") + .build(); + } else { + sourceImage = VHD.create(image.getProviderId()); + + // TODO: read the ostype from the image blob + OsFamily osFamily = image.getOperatingSystem().getFamily(); + osType = osFamily == OsFamily.WINDOWS ? "Windows" : "Linux"; + } + VHD vhd = VHD.create(blob + "vhds/" + name + ".vhd"); - OSDisk osDisk = OSDisk.create(null, name, vhd, "ReadWrite", "FromImage", null); + OSDisk osDisk = OSDisk.create(osType, name, vhd, "ReadWrite", "FromImage", sourceImage); + return StorageProfile.create(imageReference, osDisk, ImmutableList.<DataDisk>of()); } } http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/22663315/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 7af1730..24f02ea 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 @@ -16,10 +16,27 @@ */ package org.jclouds.azurecompute.arm.compute.config; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_DATADISKSIZE; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_SUBNET_ADDRESS_PREFIX; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_VNET_ADDRESS_SPACE_PREFIX; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; +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; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_IMAGE_AVAILABLE; +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; +import static org.jclouds.util.Predicates2.retry; + import java.net.URI; import java.util.List; -import javax.annotation.Resource; import javax.inject.Named; import javax.inject.Singleton; @@ -28,6 +45,7 @@ import org.jclouds.azurecompute.arm.compute.AzureComputeService; import org.jclouds.azurecompute.arm.compute.AzureComputeServiceAdapter; import org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageExtension; import org.jclouds.azurecompute.arm.compute.functions.LocationToLocation; +import org.jclouds.azurecompute.arm.compute.functions.ResourceDefinitionToCustomImage; import org.jclouds.azurecompute.arm.compute.functions.VMHardwareToHardware; import org.jclouds.azurecompute.arm.compute.functions.VMImageToImage; import org.jclouds.azurecompute.arm.compute.functions.VirtualMachineToNodeMetadata; @@ -39,7 +57,8 @@ 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.VirtualMachineProperties.ProvisioningState; +import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance; +import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance.VirtualMachineStatus.PowerState; import org.jclouds.azurecompute.arm.functions.ParseJobStatus; import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeServiceAdapter; @@ -50,11 +69,9 @@ import org.jclouds.compute.extensions.ImageExtension; import org.jclouds.compute.functions.NodeAndTemplateOptionsToStatement; import org.jclouds.compute.functions.NodeAndTemplateOptionsToStatementWithoutPublicKey; import org.jclouds.compute.options.TemplateOptions; -import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants.PollPeriod; import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; import org.jclouds.compute.strategy.CreateNodesInGroupThenAddToSet; -import org.jclouds.logging.Logger; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; @@ -62,37 +79,18 @@ import com.google.common.base.Predicate; import com.google.inject.Inject; import com.google.inject.Provides; import com.google.inject.TypeLiteral; - -import static com.google.common.base.Preconditions.checkNotNull; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_DATADISKSIZE; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_SUBNET_ADDRESS_PREFIX; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_VNET_ADDRESS_SPACE_PREFIX; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; -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; -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_IMAGE_AVAILABLE; -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; -import static org.jclouds.util.Predicates2.retry; +import com.google.inject.assistedinject.FactoryModuleBuilder; public class AzureComputeServiceContextModule extends ComputeServiceAdapterContextModule<VirtualMachine, VMHardware, VMImage, Location> { - @Resource - @Named(ComputeServiceConstants.COMPUTE_LOGGER) - protected Logger logger = Logger.NULL; - @Override protected void configure() { super.configure(); + bind(new TypeLiteral<ComputeServiceAdapter<VirtualMachine, VMHardware, VMImage, Location>>() { }).to(AzureComputeServiceAdapter.class); + bind(new TypeLiteral<Function<VMImage, org.jclouds.compute.domain.Image>>() { }).to(VMImageToImage.class); bind(new TypeLiteral<Function<VMHardware, Hardware>>() { @@ -102,12 +100,16 @@ public class AzureComputeServiceContextModule bind(new TypeLiteral<Function<Location, org.jclouds.domain.Location>>() { }).to(LocationToLocation.class); bind(ComputeService.class).to(AzureComputeService.class); + install(new LocationsFromComputeServiceAdapterModule<VirtualMachine, VMHardware, VMImage, Location>() { }); + + install(new FactoryModuleBuilder().build(ResourceDefinitionToCustomImage.Factory.class)); bind(TemplateOptions.class).to(AzureTemplateOptions.class); bind(NodeAndTemplateOptionsToStatement.class).to(NodeAndTemplateOptionsToStatementWithoutPublicKey.class); bind(CreateNodesInGroupThenAddToSet.class).to(CreateResourceGroupThenCreateNodes.class); + bind(new TypeLiteral<ImageExtension>() { }).to(AzureComputeImageExtension.class); } @@ -200,7 +202,7 @@ public class AzureComputeServiceContextModule @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, ProvisioningState.SUCCEEDED), timeouts.nodeRunning, + return retry(new VirtualMachineInStatePredicate(api, azureGroup, PowerState.RUNNING), timeouts.nodeRunning, pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); } @@ -230,7 +232,7 @@ 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 VirtualMachineInStatePredicate(api, azureGroup, ProvisioningState.DELETED), timeouts.nodeTerminated, + return retry(new VirtualMachineInStatePredicate(api, azureGroup, PowerState.STOPPED), timeouts.nodeTerminated, pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); } @@ -283,21 +285,20 @@ public class AzureComputeServiceContextModule private final AzureComputeApi api; private final String azureGroup; - private final ProvisioningState provisioningState; + private final PowerState powerState; - public VirtualMachineInStatePredicate(AzureComputeApi api, String azureGroup, ProvisioningState provisioningState) { + 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.provisioningState = provisioningState; + this.powerState = checkNotNull(powerState, "powerState must not be null"); } @Override public boolean apply(String name) { checkNotNull(name, "name cannot be null"); - VirtualMachine virtualMachine = api.getVirtualMachineApi(this.azureGroup).get(name); - if (virtualMachine == null) return false; - ProvisioningState state = virtualMachine.properties().provisioningState(); - return state == provisioningState; + VirtualMachineInstance vmInstance = api.getVirtualMachineApi(this.azureGroup).getInstanceDetails(name); + if (vmInstance == null) return false; + return powerState == vmInstance.powerState(); } } http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/22663315/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 786c17a..5817e9e 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 @@ -16,141 +16,132 @@ */ package org.jclouds.azurecompute.arm.compute.extensions; -import com.google.common.base.Predicate; -import com.google.common.base.Supplier; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.ListeningExecutorService; -import com.google.common.util.concurrent.UncheckedTimeoutException; -import com.google.gson.internal.LinkedTreeMap; -import com.google.inject.Inject; -import com.google.inject.name.Named; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; +import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.decodeFieldsFromUniqueId; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_IMAGE_AVAILABLE; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; + +import java.net.URI; +import java.util.List; +import java.util.concurrent.Callable; + +import javax.annotation.Resource; + import org.jclouds.Constants; -import org.jclouds.View; import org.jclouds.azurecompute.arm.AzureComputeApi; -import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule; -import org.jclouds.azurecompute.arm.compute.functions.VMImageToImage; +import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.AzureComputeConstants; +import org.jclouds.azurecompute.arm.compute.functions.ResourceDefinitionToCustomImage; import org.jclouds.azurecompute.arm.domain.ResourceDefinition; import org.jclouds.azurecompute.arm.domain.StorageServiceKeys; import org.jclouds.azurecompute.arm.domain.VMImage; -import org.jclouds.azurecompute.arm.domain.VirtualMachine; -import static java.lang.String.format; +import org.jclouds.azurecompute.arm.functions.CleanupResources; import org.jclouds.azurecompute.arm.util.BlobHelper; import org.jclouds.compute.domain.CloneImageTemplate; import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.ImageTemplate; import org.jclouds.compute.domain.ImageTemplateBuilder; import org.jclouds.compute.extensions.ImageExtension; -import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.AzureComputeConstants; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.logging.Logger; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Callable; +import com.google.common.base.Predicate; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.inject.Inject; +import com.google.inject.name.Named; -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_IMAGE_AVAILABLE; -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; +public class AzureComputeImageExtension implements ImageExtension { + public static final String CONTAINER_NAME = "jclouds"; + public static final String CUSTOM_IMAGE_OFFER = "custom"; + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; -public class AzureComputeImageExtension implements ImageExtension { private final AzureComputeApi api; - private final ListeningExecutorService userExecutor; - private final Supplier<View> blobstore = null; private final String group; + private final ListeningExecutorService userExecutor; private final Predicate<URI> imageAvailablePredicate; private final Predicate<String> nodeSuspendedPredicate; - private final AzureComputeConstants azureComputeConstants; - private final VMImageToImage imageReferenceToImage; - public static final String CONTAINER_NAME = "jclouds"; - public static final String CUSTOM_IMAGE_PREFIX = "#"; + private final ResourceDefinitionToCustomImage.Factory resourceDefinitionToImage; + private final CleanupResources cleanupResources; @Inject AzureComputeImageExtension(AzureComputeApi api, - @Named(TIMEOUT_IMAGE_AVAILABLE) Predicate<URI> imageAvailablePredicate, - @Named(TIMEOUT_NODE_SUSPENDED) Predicate<String> nodeSuspendedPredicate, - final AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants, - @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, - VMImageToImage imageReferenceToImage) { - this.userExecutor = userExecutor; - this.group = azureComputeConstants.azureResourceGroup(); - this.imageReferenceToImage = imageReferenceToImage; + @Named(TIMEOUT_IMAGE_AVAILABLE) Predicate<URI> imageAvailablePredicate, + @Named(TIMEOUT_NODE_SUSPENDED) Predicate<String> nodeSuspendedPredicate, + AzureComputeConstants azureComputeConstants, + @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, + ResourceDefinitionToCustomImage.Factory resourceDefinitionToImage, + CleanupResources cleanupResources) { + this.api = api; this.imageAvailablePredicate = imageAvailablePredicate; this.nodeSuspendedPredicate = nodeSuspendedPredicate; - this.azureComputeConstants = azureComputeConstants; - this.api = api; + this.group = azureComputeConstants.azureResourceGroup(); + this.userExecutor = userExecutor; + this.resourceDefinitionToImage = resourceDefinitionToImage; + this.cleanupResources = cleanupResources; } @Override public ImageTemplate buildImageTemplateFromNode(String name, String id) { - String nameLowerCase = name.toLowerCase(); - return new ImageTemplateBuilder.CloneImageTemplateBuilder().nodeId(id).name(nameLowerCase).build(); + return new ImageTemplateBuilder.CloneImageTemplateBuilder().nodeId(id).name(name.toLowerCase()).build(); } @Override public ListenableFuture<Image> createImage(ImageTemplate template) { - - final CloneImageTemplate cloneTemplate = (CloneImageTemplate) template; final String id = cloneTemplate.getSourceNodeId(); final String name = cloneTemplate.getName(); - final String storageAccountName = id.replaceAll("[^A-Za-z0-9 ]", "") + "stor"; + logger.debug(">> stopping node %s...", id); api.getVirtualMachineApi(group).stop(id); - if (nodeSuspendedPredicate.apply(id)) { - return userExecutor.submit(new Callable<Image>() { - @Override - public Image call() throws Exception { - api.getVirtualMachineApi(group).generalize(id); - - final String[] disks = new String[2]; - URI uri = api.getVirtualMachineApi(group).capture(id, cloneTemplate.getName(), CONTAINER_NAME); - if (uri != null) { - if (imageAvailablePredicate.apply(uri)) { - List<ResourceDefinition> definitions = api.getJobApi().captureStatus(uri); - if (definitions != null) { - for (ResourceDefinition definition : definitions) { - LinkedTreeMap<String, String> properties = (LinkedTreeMap<String, String>) definition.properties(); - Object storageObject = properties.get("storageProfile"); - LinkedTreeMap<String, String> properties2 = (LinkedTreeMap<String, String>) storageObject; - Object osDiskObject = properties2.get("osDisk"); - LinkedTreeMap<String, String> osProperties = (LinkedTreeMap<String, String>) osDiskObject; - Object dataDisksObject = properties2.get("dataDisks"); - ArrayList<Object> dataProperties = (ArrayList<Object>) dataDisksObject; - LinkedTreeMap<String, String> datadiskObject = (LinkedTreeMap<String, String>) dataProperties.get(0); - - disks[0] = osProperties.get("name"); - disks[1] = datadiskObject.get("name"); - - VirtualMachine vm = api.getVirtualMachineApi(group).get(id); - final VMImage ref = VMImage.create(group, storageAccountName, disks[0], disks[1], name, "custom", vm.location()); - return imageReferenceToImage.apply(ref); - } - } - } - } - throw new UncheckedTimeoutException("Image was not created within the time limit: " - + cloneTemplate.getName()); - } - }); - } else { - final String illegalStateExceptionMessage = format("Node %s was not suspended within %sms.", - id, azureComputeConstants.operationTimeout()); - throw new IllegalStateException(illegalStateExceptionMessage); - } + checkState(nodeSuspendedPredicate.apply(id), "Node %s was not suspended within the configured time limit", id); + + return userExecutor.submit(new Callable<Image>() { + @Override + public Image call() throws Exception { + logger.debug(">> generalizing virtal machine %s...", id); + api.getVirtualMachineApi(group).generalize(id); + + logger.debug(">> capturing virtual machine %s to container %s...", id, CONTAINER_NAME); + URI uri = api.getVirtualMachineApi(group).capture(id, cloneTemplate.getName(), CONTAINER_NAME); + checkState(uri != null && imageAvailablePredicate.apply(uri), + "Image %s was not created within the configured time limit", cloneTemplate.getName()); + + List<ResourceDefinition> definitions = api.getJobApi().captureStatus(uri); + checkState(definitions.size() == 1, + "Expected one resource definition after creating the image but %s were returned", definitions.size()); + + Image image = resourceDefinitionToImage.create(id, name).apply(definitions.get(0)); + logger.debug(">> created %s", image); + return image; + } + }); } @Override public boolean deleteImage(String id) { - - VMImage image = VMImageToImage.decodeFieldsFromUniqueId(id); - if (image.custom()) { - StorageServiceKeys keys = api.getStorageAccountApi(image.group()).getKeys(image.storage()); - - // This removes now all the images in this storage. At least in theory, there should be just one and if there is - // more, they should be copies of each other. - BlobHelper.deleteContainerIfExists(image.storage(), keys.key1(), "system"); - return !BlobHelper.customImageExists(image.storage(), keys.key1()); + VMImage image = decodeFieldsFromUniqueId(id); + checkArgument(image.custom(), "Only custom images can be deleted"); + + logger.debug(">> deleting image %s", id); + + StorageServiceKeys keys = api.getStorageAccountApi(image.group()).getKeys(image.storage()); + // This removes now all the images in this storage. At least in theory, + // there should be just one and if there is + // more, they should be copies of each other. + // TODO: Reuse the blobstore context in these two calls + BlobHelper.deleteContainerIfExists(image.storage(), keys.key1(), "system"); + boolean result = !BlobHelper.customImageExists(image.storage(), keys.key1()); + + if (!BlobHelper.hasContainers(image.storage(), keys.key1())) { + logger.debug(">> storage account is empty after deleting the custom image. Deleting the storage account..."); + api.getStorageAccountApi(image.group()).delete(image.storage()); + cleanupResources.deleteResourceGroupIfEmpty(image.group()); } - return false; + return result; } } http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/22663315/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 new file mode 100644 index 0000000..bf744eb --- /dev/null +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/ResourceDefinitionToCustomImage.java @@ -0,0 +1,76 @@ +/* + * 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.azurecompute.arm.compute.extensions.AzureComputeImageExtension.CUSTOM_IMAGE_OFFER; + +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.ResourceDefinition; +import org.jclouds.azurecompute.arm.domain.VMImage; +import org.jclouds.azurecompute.arm.domain.VirtualMachine; +import org.jclouds.compute.domain.Image; + +import com.google.common.base.Function; +import com.google.inject.assistedinject.Assisted; + +public class ResourceDefinitionToCustomImage implements Function<ResourceDefinition, Image> { + + public interface Factory { + 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; + + @Inject + ResourceDefinitionToCustomImage(AzureComputeApi api, AzureComputeConstants azureComputeConstants, + Function<VMImage, Image> vmImageToImage, @Assisted("nodeId") String nodeId, + @Assisted("imageName") String imageName) { + this.vmImageToImage = vmImageToImage; + this.resourceGroup = azureComputeConstants.azureResourceGroup(); + this.imageName = imageName; + this.storageAccountName = nodeId.replaceAll("[^A-Za-z0-9 ]", "") + "stor"; + this.vm = api.getVirtualMachineApi(resourceGroup).get(nodeId); + } + + @SuppressWarnings("unchecked") + @Override + public Image apply(ResourceDefinition input) { + VMImage.Builder builder = VMImage.customImage().group(resourceGroup).storage(storageAccountName).name(imageName) + .offer(CUSTOM_IMAGE_OFFER).location(vm.location()); + + Map<String, String> properties = (Map<String, String>) input.properties(); + + Object storageObject = properties.get("storageProfile"); + Map<String, String> storageProperties = (Map<String, String>) storageObject; + + Object osDiskObject = storageProperties.get("osDisk"); + Map<String, String> osProperties = (Map<String, String>) osDiskObject; + builder.vhd1(osProperties.get("name")); + + return vmImageToImage.apply(builder.build()); + } + +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/22663315/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java ---------------------------------------------------------------------- diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java index 5c10654..9d9eceb 100644 --- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java @@ -59,7 +59,7 @@ public class VMImageToImage implements Function<VMImage, Image> { } public static String encodeFieldsToUniqueIdCustom(VMImage imageReference){ - return (imageReference.globallyAvailable() ? "global" : imageReference.location()) + "/" + imageReference.group() + "/" + imageReference.storage() + "/" + imageReference.vhd1() + "/" + imageReference.offer(); + return (imageReference.globallyAvailable() ? "global" : imageReference.location()) + "/" + imageReference.group() + "/" + imageReference.storage() + "/" + imageReference.offer() + "/" + imageReference.name(); } public static VMImage decodeFieldsFromUniqueId(final String id) { @@ -71,10 +71,10 @@ public class VMImageToImage implements Function<VMImage, Image> { 0: imageReference.location) + "/" + 1: imageReference.group + "/" + 2: imageReference.storage + "/" + - 3: imageReference.vhd1 + "/" + - 4: imageReference.offer + 3: imageReference.offer + "/" + + 4: imageReference.name */ - vmImage = VMImage.create(fields[1], fields[2], fields[3], null, null, fields[4], fields[0]); + vmImage = VMImage.customImage().location(fields[0]).group(fields[1]).storage(fields[2]).vhd1(fields[3]).offer(fields[4]).build(); } else { /* id fields indexes 0: imageReference.location) + "/" + @@ -82,7 +82,7 @@ public class VMImageToImage implements Function<VMImage, Image> { 2: imageReference.offer + "/" + 3: imageReference.sku + "/" + */ - vmImage = VMImage.create(fields[1], fields[2], fields[3], null, fields[0]); + vmImage = VMImage.azureImage().location(fields[0]).publisher(fields[1]).offer(fields[2]).sku(fields[3]).build(); } return vmImage; } @@ -94,24 +94,21 @@ public class VMImageToImage implements Function<VMImage, Image> { @Override public Image apply(final VMImage image) { - if (image.custom()) { - final ImageBuilder builder = new ImageBuilder() .location(FluentIterable.from(locations.get()) .firstMatch(LocationPredicates.idEquals(image.location())) .get()) .name(image.name()) - .description("#" + image.group()) + .description(image.group()) .status(Image.Status.AVAILABLE) - .version(image.storage()) + .version("latest") .providerId(image.vhd1()) .id(encodeFieldsToUniqueIdCustom(image)); final OperatingSystem.Builder osBuilder = osFamily().apply(image); Image retimage = builder.operatingSystem(osBuilder.build()).build(); return retimage; - } else { final ImageBuilder builder = new ImageBuilder() @@ -154,16 +151,12 @@ public class VMImageToImage implements Function<VMImage, Image> { family = OsFamily.RHEL; } - String sku = image.sku(); - if (image.custom()) - sku = image.vhd1(); - // only 64bit OS images are supported by Azure ARM return OperatingSystem.builder(). family(family). is64Bit(true). - description(sku). - version(sku); + description(image.custom() ? image.vhd1() : image.sku()). + version(image.custom() ? "latest" : image.sku()); } }; } http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/22663315/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 2c28954..de373b5 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 @@ -16,6 +16,15 @@ */ package org.jclouds.azurecompute.arm.compute.functions; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Iterables.find; +import static com.google.common.collect.Iterables.transform; +import static com.google.common.collect.Iterables.tryFind; +import static org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageExtension.CONTAINER_NAME; +import static org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageExtension.CUSTOM_IMAGE_OFFER; +import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.encodeFieldsToUniqueId; + +import java.net.URI; import java.util.List; import java.util.Map; import java.util.Set; @@ -27,15 +36,18 @@ import javax.inject.Named; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.AzureComputeConstants; import org.jclouds.azurecompute.arm.domain.IdReference; -import org.jclouds.azurecompute.arm.domain.ImageReference; import org.jclouds.azurecompute.arm.domain.IpConfiguration; import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; +import org.jclouds.azurecompute.arm.domain.StorageProfile; +import org.jclouds.azurecompute.arm.domain.StorageServiceKeys; +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.VirtualMachineInstance.VirtualMachineStatus; import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance.VirtualMachineStatus.PowerState; import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties; import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties.ProvisioningState; +import org.jclouds.azurecompute.arm.util.BlobHelper; import org.jclouds.collect.Memoized; import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Image; @@ -59,10 +71,6 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.collect.Iterables.find; -import static com.google.common.collect.Iterables.transform; - public class VirtualMachineToNodeMetadata implements Function<VirtualMachine, NodeMetadata> { @Resource @@ -105,12 +113,14 @@ public class VirtualMachineToNodeMetadata implements Function<VirtualMachine, N private final Supplier<Set<? extends Location>> locations; private final Supplier<Map<String, ? extends Hardware>> hardwares; private final Map<String, Credentials> credentialStore; + private final Function<VMImage, Image> vmImageToImge; @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) { + final AzureComputeConstants azureComputeConstants, + Function<VMImage, Image> vmImageToImge) { this.api = api; this.nodeNamingConvention = namingConvention.createWithoutPrefix(); this.images = checkNotNull(images, "images cannot be null"); @@ -118,6 +128,7 @@ public class VirtualMachineToNodeMetadata implements Function<VirtualMachine, N this.hardwares = checkNotNull(hardwares, "hardwares cannot be null"); this.credentialStore = credentialStore; this.azureGroup = azureComputeConstants.azureResourceGroup(); + this.vmImageToImge = vmImageToImge; } @Override public NodeMetadata apply(VirtualMachine virtualMachine) { @@ -158,8 +169,7 @@ public class VirtualMachineToNodeMetadata implements Function<VirtualMachine, N String locationName = virtualMachine.location(); builder.location(getLocation(locationName)); - ImageReference imageReference = virtualMachine.properties().storageProfile().imageReference(); - Optional<? extends Image> image = findImage(imageReference, locationName); + Optional<? extends Image> image = findImage(virtualMachine.properties().storageProfile(), locationName); if (image.isPresent()) { builder.imageId(image.get().getId()); builder.operatingSystem(image.get().getOperatingSystem()); @@ -217,8 +227,28 @@ public class VirtualMachineToNodeMetadata implements Function<VirtualMachine, N }, null); } - protected Optional<? extends Image> findImage(ImageReference imageReference, String locatioName) { - return Optional.fromNullable(images.get().get(VMImageToImage.encodeFieldsToUniqueId(false, locatioName, imageReference))); + protected Optional<? extends Image> findImage(final StorageProfile storageProfile, String locatioName) { + if (storageProfile.imageReference() != null) { + return Optional.fromNullable(images.get().get(encodeFieldsToUniqueId(false, locatioName, storageProfile.imageReference()))); + } else { + String storageAccountNameURI = storageProfile.osDisk().vhd().uri(); + String storageAccountName = Iterables.get(Splitter.on(".").split(URI.create(storageAccountNameURI).getHost()), + 0); + StorageServiceKeys keys = api.getStorageAccountApi(azureGroup).getKeys(storageAccountName); + + // Custom image. Let's find it by uri + List<VMImage> customImagesInStorage = BlobHelper.getImages(CONTAINER_NAME, azureGroup, storageAccountName, + keys.key1(), CUSTOM_IMAGE_OFFER, locatioName); + Optional<VMImage> customImage = tryFind(customImagesInStorage, new Predicate<VMImage>() { + @Override + public boolean apply(VMImage input) { + return input.vhd1().equals(storageProfile.osDisk().image().uri()); + } + }); + + return customImage.isPresent() ? Optional.of(vmImageToImge.apply(customImage.get())) : Optional + .<Image> absent(); + } } protected Hardware getHardware(final String vmSize) { http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/22663315/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 0840689..99528fd 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,6 +16,11 @@ */ package org.jclouds.azurecompute.arm.compute.strategy; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.decodeFieldsFromUniqueId; +import static org.jclouds.util.Predicates2.retry; + import java.net.URI; import java.util.Arrays; import java.util.Map; @@ -34,6 +39,7 @@ 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.VMImage; import org.jclouds.azurecompute.arm.domain.VirtualNetwork; import org.jclouds.azurecompute.arm.features.ResourceGroupApi; import org.jclouds.azurecompute.arm.features.SubnetApi; @@ -58,10 +64,6 @@ 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 { @@ -163,9 +165,9 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco 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(); + VMImage imageRef = decodeFieldsFromUniqueId(image.getId()); + if (imageRef.custom()) { + storageAccountName = imageRef.storage(); } if (Strings.isNullOrEmpty(storageAccountName)) { @@ -177,15 +179,16 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco URI uri = api.getStorageAccountApi(resourceGroupName).create(storageAccountName, locationName, ImmutableMap.of("jclouds", name), ImmutableMap.of("accountType", StorageService.AccountType.Standard_LRS.toString())); - retry(new Predicate<URI>() { + boolean starageAccountCreated = retry(new Predicate<URI>() { @Override public boolean apply(URI uri) { return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri); } }, 60 * 2 * 1000 /* 2 minutes timeout */).apply(uri); // TODO check provisioning state of the primary - storageService = api.getStorageAccountApi(resourceGroupName).get(storageAccountName); - return storageService; + checkState(starageAccountCreated, "Storage account %s was not created in the configured timeout", + storageAccountName); + return api.getStorageAccountApi(resourceGroupName).get(storageAccountName); } /** http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/22663315/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java ---------------------------------------------------------------------- diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java index c83eafe..e4f2301 100644 --- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java @@ -16,9 +16,9 @@ */ package org.jclouds.azurecompute.arm.domain; -import com.google.auto.value.AutoValue; import org.jclouds.javax.annotation.Nullable; -import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; @AutoValue public abstract class VMImage { @@ -91,16 +91,35 @@ public abstract class VMImage { * True if custom image */ public abstract boolean custom(); - - @SerializedNames({ "publisher", "offer", "sku", "version", "location"}) - public static VMImage create(String publisher, String offer, String sku, String version, String location) { - - return new AutoValue_VMImage(publisher, offer, sku, version, location, false, null, null, null, null, null, false); + + public static Builder builder() { + return new AutoValue_VMImage.Builder(); } - - @SerializedNames({ "group", "storage", "vhd1", "vhd2", "name", "offer", "location"}) - public static VMImage create(String group, String storage, String vhd1, String vhd2, String name, String offer, String location) { - - return new AutoValue_VMImage(null, offer, null, null, location, false, group, storage, vhd1, vhd2, name, true); + + public static Builder azureImage() { + return new AutoValue_VMImage.Builder().globallyAvailable(false).custom(false); + } + + public static Builder customImage() { + return new AutoValue_VMImage.Builder().globallyAvailable(false).custom(true); + } + + @AutoValue.Builder + public abstract static class Builder { + + public abstract Builder publisher(String published); + public abstract Builder offer(String offer); + public abstract Builder sku(String sku); + public abstract Builder version(String version); + public abstract Builder location(String location); + public abstract Builder globallyAvailable(boolean globallyAvailable); + public abstract Builder group(String group); + public abstract Builder storage(String storage); + public abstract Builder vhd1(String vhd1); + public abstract Builder vhd2(String vhd2); + public abstract Builder name(String name); + public abstract Builder custom(boolean custom); + + public abstract VMImage build(); } } http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/22663315/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 f44c761..5fda879 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 @@ -14,7 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jclouds.azurecompute.arm.functions; +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; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; import java.net.URI; import java.util.List; @@ -27,10 +33,12 @@ import javax.inject.Singleton; import org.jclouds.azurecompute.arm.AzureComputeApi; 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.Subnet; +import org.jclouds.azurecompute.arm.domain.StorageServiceKeys; import org.jclouds.azurecompute.arm.domain.VirtualMachine; -import org.jclouds.azurecompute.arm.domain.VirtualNetwork; +import org.jclouds.azurecompute.arm.util.BlobHelper; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.logging.Logger; @@ -42,9 +50,6 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import static com.google.common.base.Preconditions.checkNotNull; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; - @Singleton public class CleanupResources implements Function<String, Boolean> { @@ -53,113 +58,86 @@ public class CleanupResources implements Function<String, Boolean> { protected Logger logger = Logger.NULL; protected final AzureComputeApi api; - private Predicate<URI> resourceDeleted; + private final Predicate<URI> resourceDeleted; @Inject - public CleanupResources(AzureComputeApi azureComputeApi, @Named(TIMEOUT_RESOURCE_DELETED) Predicate<URI> resourceDeleted) { + CleanupResources(AzureComputeApi azureComputeApi, @Named(TIMEOUT_RESOURCE_DELETED) Predicate<URI> resourceDeleted) { this.api = azureComputeApi; this.resourceDeleted = resourceDeleted; } @Override public Boolean apply(final String id) { - logger.debug("Destroying %s ...", id); + logger.debug(">> destroying %s ...", id); Map<String, VirtualMachine> resourceGroupNamesAndVirtualMachines = getResourceGroupNamesAndVirtualMachines(id); - if (resourceGroupNamesAndVirtualMachines.isEmpty()) 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"); + if (resourceGroupNamesAndVirtualMachines.isEmpty()) + 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"); + boolean vmDeleted = deleteVirtualMachine(group, virtualMachine); - // delete networkCardInterfaces - List<String> nics = getNetworkCardInterfaceNames(virtualMachine); - for (String nicName : nics) { + + for (String nicName : getNetworkCardInterfaceNames(virtualMachine)) { + NetworkInterfaceCard nic = api.getNetworkInterfaceCardApi(group).get(nicName); + Iterable<String> publicIps = getPublicIps(group, nic); + + logger.debug(">> destroying nic %s...", nicName); URI nicDeletionURI = api.getNetworkInterfaceCardApi(group).delete(nicName); - // todo is a collection! - boolean nicDeleted = resourceDeleted.apply(nicDeletionURI); - } - // delete virtual networks - for (VirtualNetwork virtualNetwork : api.getVirtualNetworkApi(group).list()) { - for (Subnet subnet : virtualNetwork.properties().subnets()) { - // delete subnets - api.getSubnetApi(group, virtualNetwork.name()).delete(subnet.name()); + resourceDeleted.apply(nicDeletionURI); + + for (String publicIp : publicIps) { + logger.debug(">> deleting public ip nic %s...", publicIp); + api.getPublicIPAddressApi(group).delete(publicIp); } - // todo is a collection! - boolean virtualNetworkDeleted = api.getVirtualNetworkApi(group).delete(virtualNetwork.name()); } - // delete storage account + String storageAccountNameURI = virtualMachine.properties().storageProfile().osDisk().vhd().uri(); - boolean storageAccountDeleted = api.getStorageAccountApi(group).delete(Iterables.get(Splitter.on(".").split(URI.create(storageAccountNameURI).getHost()), 0)); - - // delete resource group if empty - if (api.getVirtualMachineApi(group).list().isEmpty() && - api.getVirtualNetworkApi(group).list().isEmpty() && - api.getStorageAccountApi(group).list().isEmpty() && - api.getNetworkInterfaceCardApi(group).list().isEmpty()) { - boolean resourceGroupDeleted = resourceDeleted.apply(api.getResourceGroupApi().delete(group)); + String storageAccountName = Iterables.get(Splitter.on(".").split(URI.create(storageAccountNameURI).getHost()), 0); + StorageServiceKeys keys = api.getStorageAccountApi(group).getKeys(storageAccountName); + + // Remove the virtual machine files + logger.debug(">> deleting virtual machine disk storage..."); + BlobHelper.deleteContainerIfExists(storageAccountName, keys.key1(), "vhds"); + + if (!BlobHelper.customImageExists(storageAccountName, keys.key1())) { + logger.debug(">> deleting storage account %s...", storageAccountName); + api.getStorageAccountApi(group).delete(storageAccountName); + } else { + logger.debug(">> the storage account contains custom images. Will not delete it!"); } - return vmDeleted; - } - private List<String> getNetworkCardInterfaceNames(VirtualMachine virtualMachine) { - List<String> nics = Lists.newArrayList(); - for (IdReference idReference : virtualMachine.properties().networkProfile().networkInterfaces()) { - nics.add(Iterables.getLast(Splitter.on("/").split(idReference.id()))); - } - return nics; - } + deleteResourceGroupIfEmpty(group); - private boolean deleteVirtualMachine(String group, VirtualMachine virtualMachine) { - return resourceDeleted.apply(api.getVirtualMachineApi(group).delete(virtualMachine.name())); + return vmDeleted; } - 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); - } + public void deleteResourceGroupIfEmpty(String group) { + if (api.getVirtualMachineApi(group).list().isEmpty() + && api.getStorageAccountApi(group).list().isEmpty() + && api.getNetworkInterfaceCardApi(group).list().isEmpty() + && api.getPublicIPAddressApi(group).list().isEmpty()) { + logger.debug(">> the resource group %s is empty. Deleting...", group); + resourceDeleted.apply(api.getResourceGroupApi().delete(group)); } - return Maps.newHashMap(); } -} - -/* - for (ResourceGroup resourceGroup : api.getResourceGroupApi().list()) { - String group = resourceGroup.name(); - VirtualMachine virtualMachine = api.getVirtualMachineApi(group).get(id); - if (virtualMachine != null) { - vmDeleted = resourceDeleted.apply(api.getVirtualMachineApi(group).delete(id)); - for (IdReference idReference : virtualMachine.properties().networkProfile().networkInterfaces()) { - String nicName = Iterables.getLast(Splitter.on("/").split(idReference.id())); - NetworkInterfaceCard networkInterfaceCard = api.getNetworkInterfaceCardApi(group).get(nicName); - URI nicDeletionURI = api.getNetworkInterfaceCardApi(group).delete(nicName); - nicDeleted = resourceDeleted.apply(nicDeletionURI); - for (IpConfiguration ipConfiguration : networkInterfaceCard.properties().ipConfigurations()) { - if (ipConfiguration.properties().publicIPAddress() != null) { - String publicIpId = ipConfiguration.properties().publicIPAddress().id(); - String publicIpAddressName = Iterables.getLast(Splitter.on("/").split(publicIpId)); - publicIpAddressDeleted = api.getPublicIPAddressApi(group).delete(publicIpAddressName); - } + + private Iterable<String> getPublicIps(String group, NetworkInterfaceCard nic) { + return transform( + filter(transform(nic.properties().ipConfigurations(), new Function<IpConfiguration, IdReference>() { + @Override + public IdReference apply(IpConfiguration input) { + return input.properties().publicIPAddress(); } - } - for (VirtualNetwork virtualNetwork : api.getVirtualNetworkApi(group).list()) { - for (Subnet subnet : virtualNetwork.properties().subnets()) { - api.getSubnetApi(group, virtualNetwork.name()).delete(subnet.name()); + }), notNull()), new Function<IdReference, String>() { + @Override + public String apply(IdReference input) { + return Iterables.getLast(Splitter.on("/").split(input.id())); } - virtualNetworkDeleted = api.getVirtualNetworkApi(group).delete(virtualNetwork.name()); - } - String storageAccountNameURI = virtualMachine.properties().storageProfile().osDisk().vhd().uri(); - storageAccountDeleted = api.getStorageAccountApi(group).delete(Iterables.get(Splitter.on(".").split(URI.create(storageAccountNameURI).getHost()), 0)); - } - if (api.getVirtualMachineApi(group).list().isEmpty() && - api.getVirtualNetworkApi(group).list().isEmpty() && - api.getStorageAccountApi(group).list().isEmpty() && - api.getNetworkInterfaceCardApi(group).list().isEmpty()) { - resourceGroupDeleted = resourceDeleted.apply(api.getResourceGroupApi().delete(group)); - } - } - return vmDeleted && nicDeleted && publicIpAddressDeleted && virtualNetworkDeleted && storageAccountDeleted && resourceGroupDeleted; + }); } private List<String> getNetworkCardInterfaceNames(VirtualMachine virtualMachine) { @@ -185,4 +163,3 @@ public class CleanupResources implements Function<String, Boolean> { return Maps.newHashMap(); } } -*/ http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/22663315/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/BlobHelper.java ---------------------------------------------------------------------- diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/BlobHelper.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/BlobHelper.java index f5bfc75..2124901 100644 --- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/BlobHelper.java +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/BlobHelper.java @@ -16,76 +16,80 @@ */ package org.jclouds.azurecompute.arm.util; +import static org.jclouds.util.Closeables2.closeQuietly; + import java.util.ArrayList; import java.util.List; import org.jclouds.ContextBuilder; -import org.jclouds.azure.storage.domain.BoundedSet; import org.jclouds.azureblob.AzureBlobClient; import org.jclouds.azureblob.domain.BlobProperties; import org.jclouds.azureblob.domain.ContainerProperties; import org.jclouds.azureblob.domain.ListBlobsResponse; import org.jclouds.azurecompute.arm.domain.VMImage; -import org.jclouds.util.Closeables2; public class BlobHelper { public static void deleteContainerIfExists(String storage, String key, String containerName) { - final AzureBlobClient azureBlob = ContextBuilder.newBuilder("azureblob") - .credentials(storage, key) - .buildApi(AzureBlobClient.class); + final AzureBlobClient azureBlob = ContextBuilder.newBuilder("azureblob").credentials(storage, key) + .buildApi(AzureBlobClient.class); try { azureBlob.deleteContainer(containerName); + } finally { + closeQuietly(azureBlob); } - finally { - Closeables2.closeQuietly(azureBlob); + } + + public static boolean hasContainers(String storage, String key) { + final AzureBlobClient azureBlob = ContextBuilder.newBuilder("azureblob").credentials(storage, key) + .buildApi(AzureBlobClient.class); + + try { + return !azureBlob.listContainers().isEmpty(); + } finally { + closeQuietly(azureBlob); } } public static boolean customImageExists(String storage, String key) { - final AzureBlobClient azureBlob = ContextBuilder.newBuilder("azureblob") - .credentials(storage, key) - .buildApi(AzureBlobClient.class); + final AzureBlobClient azureBlob = ContextBuilder.newBuilder("azureblob").credentials(storage, key) + .buildApi(AzureBlobClient.class); try { return azureBlob.containerExists("system"); - } - finally { - Closeables2.closeQuietly(azureBlob); + } finally { + closeQuietly(azureBlob); } } - public static List<VMImage> getImages(String containerName, String group, - String storageAccountName, String key, String offer, String location) { - final AzureBlobClient azureBlob = ContextBuilder.newBuilder("azureblob") - .credentials(storageAccountName, key) - .buildApi(AzureBlobClient.class); - + public static List<VMImage> getImages(String containerName, String group, String storageAccountName, String key, + String offer, String location) { + final AzureBlobClient azureBlob = ContextBuilder.newBuilder("azureblob").credentials(storageAccountName, key) + .buildApi(AzureBlobClient.class); List<VMImage> list = new ArrayList<VMImage>(); + try { - BoundedSet<ContainerProperties> containerList = azureBlob.listContainers(); - for (ContainerProperties props : containerList) { - if (props.getName().equals("system")) { - ListBlobsResponse blobList = azureBlob.listBlobs("system"); - String osDisk = ""; - String dataDisk = ""; + ContainerProperties systemContainer = azureBlob.getContainerProperties("system"); + if (systemContainer != null) { + ListBlobsResponse blobList = azureBlob.listBlobs(systemContainer.getName()); + for (BlobProperties blob : blobList) { + String name = blob.getName(); - for (BlobProperties blob : blobList) { - String name = blob.getName(); + if (name.contains("-osDisk")) { + String imageName = name.substring(name.lastIndexOf('/') + 1, name.indexOf("-osDisk")); + String imageUrl = blob.getUrl().toString(); - if (dataDisk.length() == 0) dataDisk = name.substring(1 + name.lastIndexOf('/')); - else if (osDisk.length() == 0) osDisk = name.substring(1 + name.lastIndexOf('/')); + list.add(VMImage.customImage().group(group).storage(storageAccountName).vhd1(imageUrl).name(imageName) + .offer(offer).location(location).build()); } - final VMImage ref = VMImage.create(group, storageAccountName, osDisk, dataDisk, "test-create-image", "custom", location); - list.add(ref); } } + } finally { + closeQuietly(azureBlob); } - finally { - Closeables2.closeQuietly(azureBlob); - } + return list; } } http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/22663315/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 f4f5427..c338954 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 @@ -55,12 +55,9 @@ import com.google.inject.Module; */ @Test(groups = "live", singleThreaded = true, testName = "AzureComputeServiceLiveTest") public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest { - public AzureComputeServiceLiveTest() { provider = "azurecompute-arm"; - nonBlockDurationSeconds = 300; - group = "az-r"; } @Override @@ -104,17 +101,17 @@ public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest { } @Override - protected void checkUserMetadataContains(NodeMetadata node, ImmutableMap<String, String> userMetadata) { - // User metadata not yet supported - } - - @Override protected Template addRunScriptToTemplate(Template template) { template.getOptions().runScript( Statements.newStatementList(new Statement[] { AdminAccess.standard(), Statements.exec("sleep 50"), InstallJDK.fromOpenJDK() })); return template; } + + @Override + protected void checkUserMetadataContains(NodeMetadata node, ImmutableMap<String, String> userMetadata) { + // User metadata not yet supported + } @Override protected void checkTagsInNodeEquals(NodeMetadata node, ImmutableSet<String> tags) { http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/22663315/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 06f9ab7..2c48876 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 @@ -16,26 +16,27 @@ */ package org.jclouds.azurecompute.arm.compute.extensions; -import com.google.inject.Module; -import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; -import org.jclouds.azurecompute.arm.config.AzureComputeProperties; -import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; -import org.jclouds.compute.config.ComputeServiceProperties; -import org.jclouds.compute.extensions.internal.BaseImageExtensionLiveTest; -import org.jclouds.providers.ProviderMetadata; -import org.jclouds.sshj.config.SshjSshClientModule; -import org.testng.annotations.Test; - -import java.util.Properties; -import java.util.concurrent.TimeUnit; - 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.TIMEOUT_NODE_RUNNING; import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED; import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_PORT_OPEN; import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_SCRIPT_COMPLETE; +import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGIONS; + +import java.util.Properties; +import java.util.concurrent.TimeUnit; + +import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; +import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; +import org.jclouds.compute.extensions.internal.BaseImageExtensionLiveTest; +import org.jclouds.providers.ProviderMetadata; +import org.jclouds.sshj.config.SshjSshClientModule; +import org.testng.annotations.Test; + +import com.google.inject.Module; /** * Live tests for the {@link org.jclouds.compute.extensions.ImageExtension} integration. @@ -57,34 +58,25 @@ public class AzureComputeImageExtensionLiveTest extends BaseImageExtensionLiveTe @Override protected Properties setupProperties() { Properties properties = super.setupProperties(); - long scriptTimeout = TimeUnit.MILLISECONDS.convert(60, TimeUnit.MINUTES); - properties.setProperty(TIMEOUT_SCRIPT_COMPLETE, scriptTimeout + ""); - properties.setProperty(TIMEOUT_NODE_RUNNING, scriptTimeout + ""); - properties.setProperty(TIMEOUT_PORT_OPEN, scriptTimeout + ""); - properties.setProperty(TIMEOUT_NODE_TERMINATED, scriptTimeout + ""); - properties.setProperty(TIMEOUT_NODE_SUSPENDED, scriptTimeout + ""); - properties.put(RESOURCE_GROUP_NAME, "jcloudsgroup"); - - properties.put(ComputeServiceProperties.POLL_INITIAL_PERIOD, 1000); - properties.put(ComputeServiceProperties.POLL_MAX_PERIOD, 10000); - properties.setProperty(AzureComputeProperties.OPERATION_TIMEOUT, "46000000"); - properties.setProperty(AzureComputeProperties.OPERATION_POLL_INITIAL_PERIOD, "5"); - properties.setProperty(AzureComputeProperties.OPERATION_POLL_MAX_PERIOD, "15"); - properties.setProperty(AzureComputeProperties.TCP_RULE_FORMAT, "tcp_%s-%s"); - properties.setProperty(AzureComputeProperties.TCP_RULE_REGEXP, "tcp_\\d{1,5}-\\d{1,5}"); + String defaultTimeout = String.valueOf(TimeUnit.MILLISECONDS.convert(60, TimeUnit.MINUTES)); + properties.setProperty(TIMEOUT_SCRIPT_COMPLETE, defaultTimeout); + properties.setProperty(TIMEOUT_NODE_RUNNING, defaultTimeout); + 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(PROPERTY_REGIONS, "eastus"); + properties.put(IMAGE_PUBLISHERS, "Canonical"); AzureLiveTestUtils.defaultProperties(properties); checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); return properties; - } @Override protected ProviderMetadata createProviderMetadata() { - AzureComputeProviderMetadata pm = AzureComputeProviderMetadata.builder().build(); - return pm; + return AzureComputeProviderMetadata.builder().build(); } - }