diff --git a/providers/azurecompute-arm/README.md b/providers/azurecompute-arm/README.md index b1c091627c..a5a9956362 100644 --- a/providers/azurecompute-arm/README.md +++ b/providers/azurecompute-arm/README.md @@ -32,8 +32,7 @@ azure ad app create --name --password --home-page # Create a Service Principal azure ad sp create -# Output will include a value for `Object Id` - +# Output will include a value for `Object Id`, to be used in the next step ``` Run the following commands to assign roles to the service principal @@ -58,7 +57,8 @@ mvn -Dtest= \ -Dtest.azurecompute-arm.identity="" \ -Dtest.azurecompute-arm.credential="" \ -Dtest.azurecompute-arm.endpoint="https://management.azure.com/subscriptions/" \ - -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test + -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" + integration-test -Plive ``` diff --git a/providers/azurecompute-arm/pom.xml b/providers/azurecompute-arm/pom.xml index df5b835ecb..824e552c73 100644 --- a/providers/azurecompute-arm/pom.xml +++ b/providers/azurecompute-arm/pom.xml @@ -46,7 +46,7 @@ org.apache.jclouds jclouds-compute - ${project.parent.version} + ${project.version} com.google.auto.service @@ -76,11 +76,6 @@ test-jar test - - org.apache.jclouds - jclouds-compute - ${project.version} - org.apache.jclouds jclouds-compute diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeApi.java index 42749cf520..c0c0994729 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeApi.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeApi.java @@ -16,28 +16,27 @@ */ package org.jclouds.azurecompute.arm; +import java.io.Closeable; + +import javax.ws.rs.PathParam; + import org.jclouds.azurecompute.arm.features.DeploymentApi; -import org.jclouds.azurecompute.arm.util.DeploymentTemplateBuilder; import org.jclouds.azurecompute.arm.features.JobApi; import org.jclouds.azurecompute.arm.features.LocationApi; import org.jclouds.azurecompute.arm.features.NetworkInterfaceCardApi; +import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi; +import org.jclouds.azurecompute.arm.features.NetworkSecurityRuleApi; import org.jclouds.azurecompute.arm.features.OSImageApi; import org.jclouds.azurecompute.arm.features.PublicIPAddressApi; import org.jclouds.azurecompute.arm.features.ResourceGroupApi; import org.jclouds.azurecompute.arm.features.ResourceProviderApi; import org.jclouds.azurecompute.arm.features.StorageAccountApi; import org.jclouds.azurecompute.arm.features.SubnetApi; +import org.jclouds.azurecompute.arm.features.VMSizeApi; import org.jclouds.azurecompute.arm.features.VirtualMachineApi; import org.jclouds.azurecompute.arm.features.VirtualNetworkApi; -import org.jclouds.azurecompute.arm.features.VMSizeApi; -import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi; -import org.jclouds.azurecompute.arm.features.NetworkSecurityRuleApi; import org.jclouds.rest.annotations.Delegate; -import com.google.inject.Provides; -import javax.ws.rs.PathParam; -import java.io.Closeable; - /** * The Azure Resource Manager API is a REST API for managing your services and deployments. *

@@ -165,6 +164,4 @@ public interface AzureComputeApi extends Closeable { @Delegate ResourceProviderApi getResourceProviderApi(); - @Provides - DeploymentTemplateBuilder.Factory deploymentTemplateFactory(); } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeProviderMetadata.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeProviderMetadata.java index 460df67276..a434079a0b 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeProviderMetadata.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeProviderMetadata.java @@ -17,31 +17,47 @@ package org.jclouds.azurecompute.arm; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.API_VERSION_PREFIX; +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.RESOURCE_GROUP_NAME; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATION_TIMEOUT; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATION_POLL_INITIAL_PERIOD; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATION_POLL_MAX_PERIOD; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATION_TIMEOUT; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.RESOURCE_GROUP_NAME; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.STORAGE_API_VERSION; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TCP_RULE_FORMAT; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TCP_RULE_REGEXP; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_VNET_ADDRESS_SPACE_PREFIX; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_SUBNET_ADDRESS_PREFIX; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_DATADISKSIZE; - -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_IMAGE_LOGIN; - +import static org.jclouds.compute.config.ComputeServiceProperties.IMAGE_AUTHENTICATE_SUDO; +import static org.jclouds.compute.config.ComputeServiceProperties.IMAGE_LOGIN_USER; +import static org.jclouds.compute.config.ComputeServiceProperties.TEMPLATE; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED; import static org.jclouds.oauth.v2.config.CredentialType.CLIENT_CREDENTIALS_SECRET; -import static org.jclouds.oauth.v2.config.OAuthProperties.RESOURCE; import static org.jclouds.oauth.v2.config.OAuthProperties.CREDENTIAL_TYPE; +import static org.jclouds.oauth.v2.config.OAuthProperties.RESOURCE; import java.net.URI; import java.util.Properties; + import org.jclouds.azurecompute.arm.domain.Region; +import org.jclouds.azurecompute.arm.features.DeploymentApi; +import org.jclouds.azurecompute.arm.features.LocationApi; +import org.jclouds.azurecompute.arm.features.NetworkInterfaceCardApi; +import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi; +import org.jclouds.azurecompute.arm.features.NetworkSecurityRuleApi; +import org.jclouds.azurecompute.arm.features.OSImageApi; +import org.jclouds.azurecompute.arm.features.PublicIPAddressApi; +import org.jclouds.azurecompute.arm.features.ResourceGroupApi; +import org.jclouds.azurecompute.arm.features.ResourceProviderApi; +import org.jclouds.azurecompute.arm.features.StorageAccountApi; +import org.jclouds.azurecompute.arm.features.SubnetApi; +import org.jclouds.azurecompute.arm.features.VMSizeApi; +import org.jclouds.azurecompute.arm.features.VirtualMachineApi; +import org.jclouds.azurecompute.arm.features.VirtualNetworkApi; +import org.jclouds.compute.config.ComputeServiceProperties; import org.jclouds.providers.ProviderMetadata; import org.jclouds.providers.internal.BaseProviderMetadata; -import org.jclouds.compute.config.ComputeServiceProperties; - -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED; import com.google.auto.service.AutoService; @@ -72,13 +88,37 @@ 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"); properties.put(IMAGE_PUBLISHERS, "Canonical,RedHat"); - properties.put(DEFAULT_IMAGE_LOGIN, "jclouds:Password1!"); + // Default credentials for all images + properties.put(IMAGE_LOGIN_USER, "jclouds:Password12345!"); + properties.put(IMAGE_AUTHENTICATE_SUDO, "true"); + properties.put(TEMPLATE, "imageNameMatches=UbuntuServer,osVersionMatches=1[45]\\.[01][04]\\.[0-9]-LTS"); properties.put(TIMEOUT_NODE_TERMINATED, 60 * 10 * 1000); + // Api versions used in each API + properties.put(API_VERSION_PREFIX + DeploymentApi.class.getSimpleName(), "2016-02-01"); + properties.put(API_VERSION_PREFIX + LocationApi.class.getSimpleName(), "2015-11-01"); + properties.put(API_VERSION_PREFIX + NetworkInterfaceCardApi.class.getSimpleName(), "2015-06-15"); + properties.put(API_VERSION_PREFIX + NetworkSecurityGroupApi.class.getSimpleName(), "2016-03-30"); + properties.put(API_VERSION_PREFIX + NetworkSecurityRuleApi.class.getSimpleName(), "2016-03-30"); + properties.put(API_VERSION_PREFIX + OSImageApi.class.getSimpleName(), "2015-06-15"); + properties.put(API_VERSION_PREFIX + PublicIPAddressApi.class.getSimpleName(), "2015-06-15"); + properties.put(API_VERSION_PREFIX + ResourceGroupApi.class.getSimpleName(), "2015-01-01"); + properties.put(API_VERSION_PREFIX + ResourceProviderApi.class.getSimpleName(), "2015-01-01"); + properties.put(API_VERSION_PREFIX + StorageAccountApi.class.getSimpleName(), STORAGE_API_VERSION); + properties.put(API_VERSION_PREFIX + SubnetApi.class.getSimpleName(), "2015-06-15"); + properties.put(API_VERSION_PREFIX + VirtualNetworkApi.class.getSimpleName(), "2015-06-15"); + properties.put(API_VERSION_PREFIX + VMSizeApi.class.getSimpleName(), "2015-06-15"); + properties.put(API_VERSION_PREFIX + VirtualMachineApi.class.getSimpleName(), "2015-06-15"); + properties.put(API_VERSION_PREFIX + "GetVirtualMachine", "2016-03-30"); + properties.put(API_VERSION_PREFIX + "GetVirtualMachineInstance", "2016-03-30"); + properties.put(API_VERSION_PREFIX + "CreateVirtualMachine", "2016-03-30"); + properties.put(API_VERSION_PREFIX + "ListVirtualMachines", "2015-06-15"); + properties.put(API_VERSION_PREFIX + "DeleteVirtualMachine", "2016-03-30"); + return properties; } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java index 61807a9589..0e2ed641f5 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java @@ -17,164 +17,139 @@ package org.jclouds.azurecompute.arm.compute; import static com.google.common.base.Preconditions.checkState; -import static java.lang.String.format; -import static java.util.concurrent.TimeUnit.SECONDS; -import static org.jclouds.util.Predicates2.retry; +import static com.google.common.collect.Iterables.contains; +import static com.google.common.collect.Iterables.filter; +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 static org.jclouds.util.Closeables2.closeQuietly; -import java.util.Collection; 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.compute.config.AzureComputeServiceContextModule.AzureComputeConstants; -import org.jclouds.azurecompute.arm.compute.functions.DeploymentToVMDeployment; -import org.jclouds.azurecompute.arm.compute.functions.VMImageToImage; -import org.jclouds.azurecompute.arm.compute.predicates.IsDeploymentInRegions; -import org.jclouds.azurecompute.arm.domain.Deployment; -import org.jclouds.azurecompute.arm.domain.DeploymentBody; -import org.jclouds.azurecompute.arm.domain.DeploymentProperties; +import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; +import org.jclouds.azurecompute.arm.domain.DataDisk; +import org.jclouds.azurecompute.arm.domain.HardwareProfile; +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.IpConfigurationProperties; import org.jclouds.azurecompute.arm.domain.Location; +import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; +import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCardProperties; +import org.jclouds.azurecompute.arm.domain.NetworkProfile; +import org.jclouds.azurecompute.arm.domain.OSDisk; +import org.jclouds.azurecompute.arm.domain.OSProfile; import org.jclouds.azurecompute.arm.domain.Offer; +import org.jclouds.azurecompute.arm.domain.PublicIPAddress; +import org.jclouds.azurecompute.arm.domain.PublicIPAddressProperties; import org.jclouds.azurecompute.arm.domain.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.VMDeployment; +import org.jclouds.azurecompute.arm.domain.StorageService.Status; +import org.jclouds.azurecompute.arm.domain.StorageServiceKeys; +import org.jclouds.azurecompute.arm.domain.VHD; import org.jclouds.azurecompute.arm.domain.VMHardware; import org.jclouds.azurecompute.arm.domain.VMImage; import org.jclouds.azurecompute.arm.domain.VMSize; -import org.jclouds.azurecompute.arm.domain.Value; import org.jclouds.azurecompute.arm.domain.Version; -import org.jclouds.azurecompute.arm.features.DeploymentApi; +import org.jclouds.azurecompute.arm.domain.VirtualMachine; +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.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.OsFamily; import org.jclouds.compute.domain.Template; -import org.jclouds.compute.reference.ComputeServiceConstants; -import org.jclouds.domain.LoginCredentials; import org.jclouds.location.Region; -import org.jclouds.logging.Logger; 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.Supplier; -import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; -import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; -import com.google.common.net.UrlEscapers; /** * Defines the connection between the {@link AzureComputeApi} implementation and the jclouds * {@link org.jclouds.compute.ComputeService}. */ @Singleton -public class AzureComputeServiceAdapter implements ComputeServiceAdapter { +public class AzureComputeServiceAdapter implements ComputeServiceAdapter { - private String azureGroup; - protected final CleanupResources cleanupResources; - - @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> regionIds; - private final IsDeploymentInRegions isDeploymentInRegions; - private final DeploymentToVMDeployment deploymentToVMDeployment; + private final Predicate publicIpAvailable; @Inject AzureComputeServiceAdapter(final AzureComputeApi api, final AzureComputeConstants azureComputeConstants, CleanupResources cleanupResources, @Region Supplier> regionIds, - IsDeploymentInRegions isDeploymentInRegions, DeploymentToVMDeployment deploymentToVMDeployment) { + @Named("PublicIpAvailable") Predicate 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.isDeploymentInRegions = isDeploymentInRegions; - this.deploymentToVMDeployment = deploymentToVMDeployment; + this.publicIpAvailable = publicIpAvailable; } @Override - public NodeAndInitialCredentials createNodeWithGroupEncodedIntoName( + public NodeAndInitialCredentials createNodeWithGroupEncodedIntoName( final String group, final String name, final Template template) { - DeploymentTemplateBuilder deploymentTemplateBuilder = api.deploymentTemplateFactory().create(group, name, template); + AzureTemplateOptions templateOptions = template.getOptions().as(AzureTemplateOptions.class); - final String loginUser = DeploymentTemplateBuilder.getLoginUserUsername(); - final String loginPassword = DeploymentTemplateBuilder.getLoginPassword(); + // TODO Store group apart from the name to be able to identify nodes with custom names in the configured group + // TODO ARM specific options + // TODO user metadata and tags + // TODO network ids => create one nic in each network + // TODO inbound ports + + 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, template); + 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(); - DeploymentBody deploymentTemplateBody = deploymentTemplateBuilder.getDeploymentTemplate(); + VirtualMachine virtualMachine = api.getVirtualMachineApi(azureGroup).create(name, template.getLocation().getId(), virtualMachineProperties); - DeploymentProperties properties = DeploymentProperties.create(deploymentTemplateBody); - - final String deploymentTemplate = UrlEscapers.urlFormParameterEscaper().escape(deploymentTemplateBuilder.getDeploymentTemplateJson(properties)); - - logger.debug("Deployment created with name: %s group: %s", name, group); - - - final Set deployments = Sets.newHashSet(); - - final DeploymentApi deploymentApi = api.getDeploymentApi(azureGroup); - - if (!retry(new Predicate() { - @Override - public boolean apply(final String name) { - Deployment deployment = deploymentApi.create(name, deploymentTemplate); - - if (deployment != null) { - VMDeployment vmDeployment = VMDeployment.create(deployment); - deployments.add(vmDeployment); - } else { - logger.debug("Failed to create deployment!"); - } - return !deployments.isEmpty(); - } - }, azureComputeConstants.operationTimeout(), 1, SECONDS).apply(name)) { - final String illegalStateExceptionMessage = format("Deployment %s was not created within %sms so it will be destroyed.", - name, azureComputeConstants.operationTimeout()); - logger.warn(illegalStateExceptionMessage); - destroyNode(name); - throw new IllegalStateException(illegalStateExceptionMessage); - } - final VMDeployment deployment = deployments.iterator().next(); - NodeAndInitialCredentials credential; - if (template.getOptions().getPublicKey() != null){ - String privateKey = template.getOptions().getPrivateKey(); - credential = new NodeAndInitialCredentials(deployment, name, - LoginCredentials.builder().user(loginUser).privateKey(privateKey).authenticateSudo(true).build()); - } else { - credential = new NodeAndInitialCredentials(deployment, name, - LoginCredentials.builder().user(loginUser).password(loginPassword).authenticateSudo(true).build()); - } - return credential; + // 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, name, null); } @Override public Iterable listHardwareProfiles() { - final List hwProfiles = Lists.newArrayList(); - final List locationIds = Lists.newArrayList(); - - Iterable locations = listLocations(); - for (Location location : locations){ - locationIds.add(location.name()); - + for (Location location : listLocations()) { Iterable vmSizes = api.getVMSizeApi(location.name()).list(); - for (VMSize vmSize : vmSizes){ VMHardware hwProfile = VMHardware.create( vmSize.name(), @@ -188,22 +163,8 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter hwProfiles, Collection locations) { - Multimap hwMap = ArrayListMultimap.create(); - for (VMHardware hw : hwProfiles) { - hwMap.put(hw.name(), hw.location()); - } - - /// TODO - // for (VMHardware hw : hwProfiles) { - // hw.globallyAvailable() = hwMap.get(hw.name()).containsAll(locations); - // } - } private List getImagesFromPublisher(String publisherName, String location) { List osImagesRef = Lists.newArrayList(); @@ -216,7 +177,8 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter 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); } } @@ -235,7 +197,6 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listImages() { - final List osImages = Lists.newArrayList(); for (Location location : listLocations()){ @@ -245,24 +206,51 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter storages = api.getStorageAccountApi(azureGroup).list(); for (StorageService storage : storages) { String name = storage.name(); - String key = api.getStorageAccountApi(azureGroup).getKeys(name).key1(); - List images = BlobHelper.getImages("jclouds", azureGroup, storage.name(), key, - "custom", storage.location()); - osImages.addAll(images); + StorageService storageService = api.getStorageAccountApi(azureGroup).get(name); + if (storageService != null + && Status.Succeeded == storageService.storageServiceProperties().provisioningState()) { + String key = api.getStorageAccountApi(azureGroup).getKeys(name).key1(); + BlobHelper blobHelper = new BlobHelper(storage.name(), key); + try { + List images = blobHelper.getImages(CONTAINER_NAME, azureGroup, CUSTOM_IMAGE_OFFER, + storage.location()); + osImages.addAll(images); + } finally { + closeQuietly(blobHelper); + } + } } + return osImages; } @Override public VMImage getImage(final String id) { - VMImage image = VMImageToImage.decodeFieldsFromUniqueId(id); + VMImage image = decodeFieldsFromUniqueId(id); if (image.custom()) { - String key = api.getStorageAccountApi(azureGroup).getKeys(image.storage()).key1(); - if (BlobHelper.customImageExists(image.storage(), key)) - return image; - else + VMImage customImage = null; + StorageServiceKeys keys = api.getStorageAccountApi(azureGroup).getKeys(image.storage()); + if (keys == null) { + // If the storage account for the image does not exist, it means the image was deleted return null; - + } + + BlobHelper blobHelper = new BlobHelper(image.storage(), keys.key1()); + try { + if (blobHelper.customImageExists()) { + List customImagesInStorage = blobHelper.getImages(CONTAINER_NAME, azureGroup, + CUSTOM_IMAGE_OFFER, image.location()); + customImage = find(customImagesInStorage, new Predicate() { + @Override + public boolean apply(VMImage input) { + return id.equals(encodeFieldsToUniqueIdCustom(input)); + } + }, null); + } + } finally { + closeQuietly(blobHelper); + } + return customImage; } String location = image.location(); @@ -273,7 +261,8 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter 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; } @@ -313,13 +302,8 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listNodes() { - return FluentIterable.from(api.getDeploymentApi(azureGroup).list()) - .filter(isDeploymentInRegions) - .filter(new Predicate() { - @Override - public boolean apply(Deployment deployment) { - Value storageAccountNameValue = deployment.properties().parameters().get("storageAccountName"); - String storageAccountName = storageAccountNameValue.value(); - String key = api.getStorageAccountApi(azureGroup).getKeys(storageAccountName).key1(); - return !BlobHelper.customImageExists(storageAccountName, key); - } - }) - .transform(deploymentToVMDeployment) - .toList(); + public Iterable listNodes() { + return api.getVirtualMachineApi(azureGroup).list(); } @Override - public Iterable listNodesByIds(final Iterable ids) { - return Iterables.filter(listNodes(), new Predicate() { + public Iterable listNodesByIds(final Iterable ids) { + return filter(listNodes(), new Predicate() { @Override - public boolean apply(final VMDeployment input) { - return Iterables.contains(ids, input.deployment().name()); + public boolean apply(VirtualMachine virtualMachine) { + return contains(ids, virtualMachine.id()); } }); } + + + 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 (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), + template.getOptions().getPublicKey()) + )) + ); + builder.linuxConfiguration(linuxConfiguration); + } else { + builder.adminPassword(adminPassword); + } + return builder.build(); + } + + private NetworkInterfaceCard createNetworkInterfaceCard(String subnetId, String name, String locationName) { + final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(azureGroup); + + PublicIPAddressProperties properties = + PublicIPAddressProperties.builder() + .publicIPAllocationMethod("Static") + .idleTimeoutInMinutes(4) + .build(); + + String publicIpAddressName = "public-address-" + name; + PublicIPAddress ip = ipApi.createOrUpdate(publicIpAddressName, locationName, ImmutableMap.of("jclouds", name), properties); + + checkState(publicIpAvailable.apply(publicIpAddressName), + "Public IP was not provisioned in the configured timeout"); + + final NetworkInterfaceCardProperties networkInterfaceCardProperties = + NetworkInterfaceCardProperties.builder() + .ipConfigurations(ImmutableList.of( + IpConfiguration.builder() + .name("ipConfig-" + name) + .properties(IpConfigurationProperties.builder() + .privateIPAllocationMethod("Dynamic") + .publicIPAddress(IdReference.create(ip.id())) + .subnet(IdReference.create(subnetId)) + .build()) + .build())) + .build(); + + String networkInterfaceCardName = "jc-nic-" + name; + return api.getNetworkInterfaceCardApi(azureGroup).createOrUpdate(networkInterfaceCardName, locationName, networkInterfaceCardProperties, ImmutableMap.of("jclouds", name)); + } + + private StorageProfile createStorageProfile(String name, Image image, String blob) { + 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(osType, name, vhd, "ReadWrite", "FromImage", sourceImage); + + return StorageProfile.create(imageReference, osDisk, ImmutableList.of()); + } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/config/AzureComputeServiceContextModule.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/config/AzureComputeServiceContextModule.java index 6033f42150..24f02ead6c 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/config/AzureComputeServiceContextModule.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/config/AzureComputeServiceContextModule.java @@ -16,55 +16,8 @@ */ package org.jclouds.azurecompute.arm.compute.config; -import java.net.URI; -import java.util.List; - -import javax.annotation.Resource; -import javax.inject.Named; -import javax.inject.Singleton; - -import org.jclouds.azurecompute.arm.AzureComputeApi; -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.DeploymentToNodeMetadata; -import org.jclouds.azurecompute.arm.compute.functions.LocationToLocation; -import org.jclouds.azurecompute.arm.compute.functions.VMHardwareToHardware; -import org.jclouds.azurecompute.arm.compute.functions.VMImageToImage; -import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; -import org.jclouds.azurecompute.arm.compute.strategy.AzurePopulateDefaultLoginCredentialsForImageStrategy; -import org.jclouds.azurecompute.arm.compute.strategy.CreateResourceGroupThenCreateNodes; -import org.jclouds.azurecompute.arm.domain.Location; -import org.jclouds.azurecompute.arm.domain.ResourceDefinition; -import org.jclouds.azurecompute.arm.domain.VMDeployment; -import org.jclouds.azurecompute.arm.domain.VMHardware; -import org.jclouds.azurecompute.arm.domain.VMImage; -import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance; -import org.jclouds.azurecompute.arm.functions.ParseJobStatus; -import org.jclouds.compute.ComputeService; -import org.jclouds.compute.ComputeServiceAdapter; -import org.jclouds.compute.config.ComputeServiceAdapterContextModule; -import org.jclouds.compute.domain.Hardware; -import org.jclouds.compute.domain.NodeMetadata; -import org.jclouds.compute.extensions.ImageExtension; -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.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy; -import org.jclouds.logging.Logger; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Function; -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_IMAGE_LOGIN; 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; @@ -76,38 +29,87 @@ import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TCP_RUL 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; -public class AzureComputeServiceContextModule - extends ComputeServiceAdapterContextModule { +import java.net.URI; +import java.util.List; - @Resource - @Named(ComputeServiceConstants.COMPUTE_LOGGER) - protected Logger logger = Logger.NULL; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.azurecompute.arm.AzureComputeApi; +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; +import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; +import org.jclouds.azurecompute.arm.compute.strategy.CreateResourceGroupThenCreateNodes; +import org.jclouds.azurecompute.arm.domain.Location; +import org.jclouds.azurecompute.arm.domain.PublicIPAddress; +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.VirtualMachineInstance.VirtualMachineStatus.PowerState; +import org.jclouds.azurecompute.arm.functions.ParseJobStatus; +import org.jclouds.compute.ComputeService; +import org.jclouds.compute.ComputeServiceAdapter; +import org.jclouds.compute.config.ComputeServiceAdapterContextModule; +import org.jclouds.compute.domain.Hardware; +import org.jclouds.compute.domain.NodeMetadata; +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.PollPeriod; +import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; +import org.jclouds.compute.strategy.CreateNodesInGroupThenAddToSet; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.inject.Inject; +import com.google.inject.Provides; +import com.google.inject.TypeLiteral; +import com.google.inject.assistedinject.FactoryModuleBuilder; + +public class AzureComputeServiceContextModule + extends ComputeServiceAdapterContextModule { @Override protected void configure() { super.configure(); - bind(new TypeLiteral>() { + + bind(new TypeLiteral>() { }).to(AzureComputeServiceAdapter.class); + bind(new TypeLiteral>() { }).to(VMImageToImage.class); bind(new TypeLiteral>() { }).to(VMHardwareToHardware.class); - bind(new TypeLiteral>() { - }).to(DeploymentToNodeMetadata.class); + bind(new TypeLiteral>() { + }).to(VirtualMachineToNodeMetadata.class); bind(new TypeLiteral>() { }).to(LocationToLocation.class); bind(ComputeService.class).to(AzureComputeService.class); - install(new LocationsFromComputeServiceAdapterModule() { + + install(new LocationsFromComputeServiceAdapterModule() { }); + + install(new FactoryModuleBuilder().build(ResourceDefinitionToCustomImage.Factory.class)); bind(TemplateOptions.class).to(AzureTemplateOptions.class); - bind(PopulateDefaultLoginCredentialsForImageStrategy.class).to(AzurePopulateDefaultLoginCredentialsForImageStrategy.class); - //bind(TemplateOptionsToStatement.class).to(TemplateOptionsToStatementWithoutPublicKey.class); + bind(NodeAndTemplateOptionsToStatement.class).to(NodeAndTemplateOptionsToStatementWithoutPublicKey.class); bind(CreateNodesInGroupThenAddToSet.class).to(CreateResourceGroupThenCreateNodes.class); + bind(new TypeLiteral() { }).to(AzureComputeImageExtension.class); } @@ -143,10 +145,6 @@ public class AzureComputeServiceContextModule @Inject private String azureImagePublishersProperty; - @Named(DEFAULT_IMAGE_LOGIN) - @Inject - private String azureDefaultImageLoginProperty; - @Named(DEFAULT_VNET_ADDRESS_SPACE_PREFIX) @Inject private String azureDefaultVnetAddressPrefixProperty; @@ -171,10 +169,6 @@ public class AzureComputeServiceContextModule return azureImagePublishersProperty; } - public String azureDefaultImageLogin() { - return azureDefaultImageLoginProperty; - } - public String azureDefaultVnetAddressPrefixProperty() { return azureDefaultVnetAddressPrefixProperty; } @@ -204,6 +198,14 @@ public class AzureComputeServiceContextModule } } + @Provides + @com.google.inject.name.Named(TIMEOUT_NODE_RUNNING) + protected Predicate provideVirtualMachineRunningPredicate(final AzureComputeApi api, final AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants, Timeouts timeouts, PollPeriod pollPeriod) { + String azureGroup = azureComputeConstants.azureResourceGroup(); + return retry(new VirtualMachineInStatePredicate(api, azureGroup, PowerState.RUNNING), timeouts.nodeRunning, + pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); + } + @Provides @Named(TIMEOUT_NODE_TERMINATED) protected Predicate provideNodeTerminatedPredicate(final AzureComputeApi api, Timeouts timeouts, PollPeriod pollPeriod) { @@ -230,7 +232,17 @@ public class AzureComputeServiceContextModule protected Predicate 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, PowerState.STOPPED), timeouts.nodeTerminated, + pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); + } + + @Provides + @Named("PublicIpAvailable") + protected Predicate providePublicIpAvailablePredicate(final AzureComputeApi api, final AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants, + Timeouts timeouts, PollPeriod pollPeriod) { + String azureGroup = azureComputeConstants.azureResourceGroup(); + return retry(new PublicIpAvailablePredicate(api, azureGroup), azureComputeConstants.operationTimeout(), + azureComputeConstants.operationPollInitialPeriod(), azureComputeConstants.operationPollMaxPeriod()); } @VisibleForTesting @@ -269,12 +281,34 @@ public class AzureComputeServiceContextModule } @VisibleForTesting - static class NodeSuspendedPredicate implements Predicate { + static class VirtualMachineInStatePredicate implements Predicate { + + private final AzureComputeApi api; + private final String azureGroup; + private final PowerState powerState; + + public VirtualMachineInStatePredicate(AzureComputeApi api, String azureGroup, PowerState powerState) { + this.api = checkNotNull(api, "api must not be null"); + this.azureGroup = checkNotNull(azureGroup, "azuregroup must not be null"); + this.powerState = checkNotNull(powerState, "powerState must not be null"); + } + + @Override + public boolean apply(String name) { + checkNotNull(name, "name cannot be null"); + VirtualMachineInstance vmInstance = api.getVirtualMachineApi(this.azureGroup).getInstanceDetails(name); + if (vmInstance == null) return false; + return powerState == vmInstance.powerState(); + } + } + + @VisibleForTesting + static class PublicIpAvailablePredicate implements Predicate { private final AzureComputeApi api; private final String azureGroup; - public NodeSuspendedPredicate(AzureComputeApi api, String azureGroup) { + public PublicIpAvailablePredicate(AzureComputeApi api, String azureGroup) { this.api = checkNotNull(api, "api must not be null"); this.azureGroup = checkNotNull(azureGroup, "azuregroup must not be null"); } @@ -282,17 +316,10 @@ public class AzureComputeServiceContextModule @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 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"); + PublicIPAddress publicIp = api.getPublicIPAddressApi(azureGroup).get(name); + if (publicIp == null) return false; + return publicIp.properties().provisioningState().equalsIgnoreCase("Succeeded"); } } + } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtension.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtension.java index 786c17a62f..99c9c6cde1 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtension.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtension.java @@ -16,141 +16,137 @@ */ 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 static org.jclouds.util.Closeables2.closeQuietly; + +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 java.net.URI; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Callable; - -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_IMAGE_AVAILABLE; -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.logging.Logger; +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; 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; + private final AzureComputeApi api; - private final ListeningExecutorService userExecutor; - private final Supplier blobstore = null; private final String group; + private final ListeningExecutorService userExecutor; private final Predicate imageAvailablePredicate; private final Predicate 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 imageAvailablePredicate, - @Named(TIMEOUT_NODE_SUSPENDED) Predicate 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 imageAvailablePredicate, + @Named(TIMEOUT_NODE_SUSPENDED) Predicate 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 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() { - @Override - public Image call() throws Exception { - api.getVirtualMachineApi(group).generalize(id); + checkState(nodeSuspendedPredicate.apply(id), "Node %s was not suspended within the configured time limit", 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 definitions = api.getJobApi().captureStatus(uri); - if (definitions != null) { - for (ResourceDefinition definition : definitions) { - LinkedTreeMap properties = (LinkedTreeMap) definition.properties(); - Object storageObject = properties.get("storageProfile"); - LinkedTreeMap properties2 = (LinkedTreeMap) storageObject; - Object osDiskObject = properties2.get("osDisk"); - LinkedTreeMap osProperties = (LinkedTreeMap) osDiskObject; - Object dataDisksObject = properties2.get("dataDisks"); - ArrayList dataProperties = (ArrayList) dataDisksObject; - LinkedTreeMap datadiskObject = (LinkedTreeMap) dataProperties.get(0); + return userExecutor.submit(new Callable() { + @Override + public Image call() throws Exception { + logger.debug(">> generalizing virtal machine %s...", id); + api.getVirtualMachineApi(group).generalize(id); - disks[0] = osProperties.get("name"); - disks[1] = datadiskObject.get("name"); + 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()); - 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); - } + List 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 = decodeFieldsFromUniqueId(id); + checkArgument(image.custom(), "Only custom images can be deleted"); - VMImage image = VMImageToImage.decodeFieldsFromUniqueId(id); - if (image.custom()) { - StorageServiceKeys keys = api.getStorageAccountApi(image.group()).getKeys(image.storage()); + logger.debug(">> deleting image %s", id); - // This removes now all the images in this storage. At least in theory, there should be just one and if there is + StorageServiceKeys keys = api.getStorageAccountApi(image.group()).getKeys(image.storage()); + BlobHelper blobHelper = new BlobHelper(image.storage(), keys.key1()); + + try { + // This removes now all the images in this storage. At least in theory, + // there should be just one and if there is // more, they should be copies of each other. - BlobHelper.deleteContainerIfExists(image.storage(), keys.key1(), "system"); - return !BlobHelper.customImageExists(image.storage(), keys.key1()); - } + blobHelper.deleteContainerIfExists("system"); + boolean result = !blobHelper.customImageExists(); - return false; + if (!blobHelper.hasContainers()) { + 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 result; + } finally { + closeQuietly(blobHelper); + } } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/DeploymentToNodeMetadata.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/DeploymentToNodeMetadata.java deleted file mode 100644 index 532e786c92..0000000000 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/DeploymentToNodeMetadata.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jclouds.azurecompute.arm.compute.functions; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.inject.Inject; - -import com.google.common.collect.Sets; -import org.jclouds.azurecompute.arm.AzureComputeApi; -import org.jclouds.azurecompute.arm.domain.ComputeNode; -import org.jclouds.azurecompute.arm.domain.Deployment; -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.PublicIPAddress; -import org.jclouds.azurecompute.arm.domain.VMDeployment; -import org.jclouds.azurecompute.arm.domain.VMHardware; -import org.jclouds.azurecompute.arm.domain.VMImage; -import org.jclouds.azurecompute.arm.domain.VMSize; -import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance; -import org.jclouds.azurecompute.arm.util.DeploymentTemplateBuilder; -import org.jclouds.azurecompute.arm.util.GetEnumValue; -import org.jclouds.compute.domain.NodeMetadata; -import org.jclouds.compute.domain.NodeMetadataBuilder; -import org.jclouds.compute.functions.GroupNamingConvention; -import org.jclouds.domain.Credentials; -import org.jclouds.domain.Location; -import com.google.common.base.Function; -import com.google.common.collect.ImmutableMap; -import org.jclouds.domain.LoginCredentials; -import org.jclouds.compute.domain.Image; -import org.jclouds.compute.domain.Hardware; - -public class DeploymentToNodeMetadata implements Function { - - public static final String JCLOUDS_DEFAULT_USERNAME = "root"; - public static final String AZURE_LOGIN_USERNAME = DeploymentTemplateBuilder.getLoginUserUsername(); - public static final String AZURE_LOGIN_PASSWORD = DeploymentTemplateBuilder.getLoginPassword(); - - private static final Map INSTANCESTATUS_TO_NODESTATUS = - ImmutableMap.builder(). - put(ComputeNode.Status.GOOD, NodeMetadata.Status.RUNNING). - put(ComputeNode.Status.BAD, NodeMetadata.Status.ERROR). - put(ComputeNode.Status.UNRECOGNIZED, NodeMetadata.Status.UNRECOGNIZED). - build(); - - // When using the Deployment API to deploy an ARM template, the deployment goes through - // stages. Accepted -> Running -> Succeeded. Only when the deployment has SUCCEEDED is - // the resource deployed using the template actually ready. - // - // To get details about the resource(s) deployed via template, one needs to query the - // various resources after the deployment has "SUCCEEDED". - private static final Map STATUS_TO_NODESTATUS = - ImmutableMap.builder(). - put(Deployment.ProvisioningState.ACCEPTED, NodeMetadata.Status.PENDING). - put(Deployment.ProvisioningState.READY, NodeMetadata.Status.PENDING). - put(Deployment.ProvisioningState.RUNNING, NodeMetadata.Status.PENDING). - put(Deployment.ProvisioningState.CANCELED, NodeMetadata.Status.TERMINATED). - put(Deployment.ProvisioningState.FAILED, NodeMetadata.Status.ERROR). - put(Deployment.ProvisioningState.DELETED, NodeMetadata.Status.TERMINATED). - put(Deployment.ProvisioningState.SUCCEEDED, NodeMetadata.Status.RUNNING). - put(Deployment.ProvisioningState.UNRECOGNIZED, NodeMetadata.Status.UNRECOGNIZED). - build(); - - public static Deployment.ProvisioningState provisioningStateFromString(final String text) { - return (Deployment.ProvisioningState) GetEnumValue.fromValueOrDefault(text, Deployment.ProvisioningState.UNRECOGNIZED); - } - - private final AzureComputeApi api; - - private final LocationToLocation locationToLocation; - - private final GroupNamingConvention nodeNamingConvention; - - private final VMImageToImage vmImageToImage; - - private final VMHardwareToHardware vmHardwareToHardware; - - private final Map credentialStore; - - @Inject - DeploymentToNodeMetadata( - AzureComputeApi api, - LocationToLocation locationToLocation, - GroupNamingConvention.Factory namingConvention, VMImageToImage vmImageToImage, - VMHardwareToHardware vmHardwareToHardware, Map credentialStore) { - - this.nodeNamingConvention = namingConvention.createWithoutPrefix(); - this.locationToLocation = locationToLocation; - this.vmImageToImage = vmImageToImage; - this.vmHardwareToHardware = vmHardwareToHardware; - this.credentialStore = credentialStore; - this.api = api; - } - - @Override - public NodeMetadata apply(final VMDeployment from) { - final NodeMetadataBuilder builder = new NodeMetadataBuilder(); - final Deployment deployment = from.deployment(); - builder.id(deployment.name()); - builder.providerId(deployment.name()); - builder.name(deployment.name()); - String group = this.nodeNamingConvention.extractGroup(deployment.name()); - builder.group(group); - if (from.tags() != null) - builder.tags(from.tags()); - if (from.userMetaData() != null) - builder.userMetadata(from.userMetaData()); - - NodeMetadata.Status status = STATUS_TO_NODESTATUS.get(provisioningStateFromString(deployment.properties().provisioningState())); - if (status == NodeMetadata.Status.RUNNING && from.vm() != null && from.vm().statuses() != null) { - List statuses = from.vm().statuses(); - for (int c = 0; c < statuses.size(); c++) { - if (statuses.get(c).code().substring(0, 10).equals("PowerState")) { - if (statuses.get(c).displayStatus().equals("VM running")) { - status = NodeMetadata.Status.RUNNING; - } else if (statuses.get(c).displayStatus().equals("VM stopped")) { - status = NodeMetadata.Status.SUSPENDED; - } - break; - } - } - } - - builder.status(status); - - if (from.vm() != null) { - builder.hostname(deployment.name() + "pc"); - } - - Credentials credentials = credentialStore.get("node#" + from.deployment().name()); - if (credentials != null && credentials.identity.equals(JCLOUDS_DEFAULT_USERNAME)) { - credentials = new Credentials(AZURE_LOGIN_USERNAME, credentials.credential); - } - else if (credentials == null) { - String username = AZURE_LOGIN_USERNAME; - String password = AZURE_LOGIN_PASSWORD; - if (username == null) { - username = "jclouds"; - } - if (password == null) { - password = "Password1!"; - } - - credentials = new Credentials(username, password); - } - builder.credentials(LoginCredentials.fromCredentials(credentials)); - - final Set publicIpAddresses = Sets.newLinkedHashSet(); - if (from.ipAddressList() != null) { - for (int c = 0; c < from.ipAddressList().size(); c++) { - PublicIPAddress ip = from.ipAddressList().get(c); - if (ip != null && ip.properties() != null && ip.properties().ipAddress() != null) - { - publicIpAddresses.add(ip.properties().ipAddress()); - break; - } - } - if (publicIpAddresses.size() > 0) - builder.publicAddresses(publicIpAddresses); - } - final Set privateIpAddresses = Sets.newLinkedHashSet(); - if (from.networkInterfaceCards() != null) { - for (NetworkInterfaceCard nic : from.networkInterfaceCards()) { - if (nic != null && nic.properties() != null && nic.properties().ipConfigurations() != null) { - for (IpConfiguration ip : nic.properties().ipConfigurations()) { - if (ip != null && ip.properties() != null && ip.properties().privateIPAddress() != null) { - privateIpAddresses.add(ip.properties().privateIPAddress()); - } - } - } - } - if (!privateIpAddresses.isEmpty()) { - builder.privateAddresses(privateIpAddresses); - } - } - - org.jclouds.azurecompute.arm.domain.Location myLocation = null; - if (from.virtualMachine() != null) { - String locationName = from.virtualMachine().location(); - List locations = api.getLocationApi().list(); - - for (org.jclouds.azurecompute.arm.domain.Location location : locations) { - if (location.name().equals(locationName)) { - myLocation = location; - break; - } - } - Location jLocation = this.locationToLocation.apply(myLocation); - builder.location(jLocation); - - ImageReference imageReference = from.virtualMachine().properties().storageProfile().imageReference(); - - if (imageReference != null) { - VMImage vmImage = VMImage.create(imageReference.publisher(), imageReference.offer(), imageReference.sku(), - imageReference.version(), locationName); - Image image = vmImageToImage.apply(vmImage); - builder.imageId(image.getId()); - } - - VMSize myVMSize = null; - String vmSizeName = from.virtualMachine().properties().hardwareProfile().vmSize(); - List vmSizes = api.getVMSizeApi(locationName).list(); - for (VMSize vmSize : vmSizes) { - if (vmSize.name().equals(vmSizeName)) { - myVMSize = vmSize; - break; - } - } - - VMHardware hwProfile = VMHardware.create( - myVMSize.name(), - myVMSize.numberOfCores(), - myVMSize.osDiskSizeInMB(), - myVMSize.resourceDiskSizeInMB(), - myVMSize.memoryInMB(), - myVMSize.maxDataDiskCount(), - locationName, - false); - - Hardware hardware = vmHardwareToHardware.apply(hwProfile); - builder.hardware(hardware); - } - - return builder.build(); - } -} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/DeploymentToVMDeployment.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/DeploymentToVMDeployment.java deleted file mode 100644 index 31f1a58586..0000000000 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/DeploymentToVMDeployment.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jclouds.azurecompute.arm.compute.functions; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import org.jclouds.azurecompute.arm.AzureComputeApi; -import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule; -import org.jclouds.azurecompute.arm.domain.Deployment; -import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; -import org.jclouds.azurecompute.arm.domain.PublicIPAddress; -import org.jclouds.azurecompute.arm.domain.VMDeployment; -import org.jclouds.azurecompute.arm.domain.VirtualMachine; -import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance; - -import com.google.common.base.Function; - -/** - * Converts an Deployment into a VMDeployment. - */ -@Singleton -public class DeploymentToVMDeployment implements Function { - - private final AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants; - - private final AzureComputeApi api; - - @Inject - DeploymentToVMDeployment(AzureComputeApi api, final AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants) { - this.api = api; - this.azureComputeConstants = azureComputeConstants; - } - - @Override - public VMDeployment apply(final Deployment deployment) { - String id = deployment.id(); - List ipAddressList = getIPAddresses(deployment); - List networkInterfaceCards = getNetworkInterfaceCards(deployment); - VirtualMachine vm = api.getVirtualMachineApi(azureComputeConstants.azureResourceGroup()).get(id); - VirtualMachineInstance vmInstanceDetails = api.getVirtualMachineApi(azureComputeConstants.azureResourceGroup()).getInstanceDetails(id); - Map userMetaData = null; - Iterable tags = null; - if (vm != null && vm.tags() != null) { - userMetaData = vm.tags(); - String tagString = userMetaData.get("tags"); - tags = Arrays.asList(tagString.split(",")); - } - return VMDeployment.create(deployment, ipAddressList, vmInstanceDetails, vm, networkInterfaceCards, userMetaData, tags); - } - - private List getIPAddresses(Deployment deployment) { - List list = new ArrayList(); - String resourceGroup = getResourceGroupFromId(deployment.id()); - - if (deployment.properties() != null && deployment.properties().dependencies() != null) { - List dependencies = deployment.properties().dependencies(); - for (int d = 0; d < dependencies.size(); d++) { - if (dependencies.get(d).resourceType().equals("Microsoft.Network/networkInterfaces")) { - List dependsOn = dependencies.get(d).dependsOn(); - for (int e = 0; e < dependsOn.size(); e++) { - if (dependsOn.get(e).resourceType().equals("Microsoft.Network/publicIPAddresses")) { - String resourceName = dependsOn.get(e).resourceName(); - PublicIPAddress ip = api.getPublicIPAddressApi(resourceGroup).get(resourceName); - list.add(ip); - break; - } - } - } - } - } - return list; - } - - private String getResourceGroupFromId(String id) { - String searchStr = "/resourceGroups/"; - int indexStart = id.lastIndexOf(searchStr) + searchStr.length(); - searchStr = "/providers/"; - int indexEnd = id.lastIndexOf(searchStr); - - String resourceGroup = id.substring(indexStart, indexEnd); - return resourceGroup; - } - - private List getNetworkInterfaceCards(Deployment deployment) { - List result = new ArrayList(); - - String resourceGroup = getResourceGroupFromId(deployment.id()); - - if (deployment.properties() != null && deployment.properties().dependencies() != null) { - for (Deployment.Dependency dependency : deployment.properties().dependencies()) { - if (dependency.resourceType().equals("Microsoft.Network/networkInterfaces")) { - String resourceName = dependency.resourceName(); - NetworkInterfaceCard nic = api.getNetworkInterfaceCardApi(resourceGroup).get(resourceName); - result.add(nic); - } - } - } - return result; - } - -} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/ResourceDefinitionToCustomImage.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/ResourceDefinitionToCustomImage.java new file mode 100644 index 0000000000..cce6b50847 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/ResourceDefinitionToCustomImage.java @@ -0,0 +1,78 @@ +/* + * 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.azurecompute.arm.functions.StorageProfileToStorageAccountName; +import org.jclouds.compute.domain.Image; + +import com.google.common.base.Function; +import com.google.inject.assistedinject.Assisted; + +public class ResourceDefinitionToCustomImage implements Function { + + public interface Factory { + ResourceDefinitionToCustomImage create(@Assisted("nodeId") String nodeId, @Assisted("imageName") String imageName); + } + + private final String resourceGroup; + private final Function vmImageToImage; + private final String imageName; + private final String storageAccountName; + private final VirtualMachine vm; + + @Inject + ResourceDefinitionToCustomImage(AzureComputeApi api, AzureComputeConstants azureComputeConstants, + StorageProfileToStorageAccountName storageProfileToStorageAccountName, + Function vmImageToImage, @Assisted("nodeId") String nodeId, + @Assisted("imageName") String imageName) { + this.vmImageToImage = vmImageToImage; + this.resourceGroup = azureComputeConstants.azureResourceGroup(); + this.imageName = imageName; + this.vm = api.getVirtualMachineApi(resourceGroup).get(nodeId); + this.storageAccountName = storageProfileToStorageAccountName.apply(vm.properties().storageProfile()); + } + + @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 properties = (Map) input.properties(); + + Object storageObject = properties.get("storageProfile"); + Map storageProperties = (Map) storageObject; + + Object osDiskObject = storageProperties.get("osDisk"); + Map osProperties = (Map) osDiskObject; + builder.vhd1(osProperties.get("name")); + + return vmImageToImage.apply(builder.build()); + } + +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java index f784842ef7..9d9eceb2b8 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java @@ -16,58 +16,50 @@ */ package org.jclouds.azurecompute.arm.compute.functions; -import static com.google.common.base.Preconditions.checkNotNull; -import static org.jclouds.azurecompute.arm.compute.functions.DeploymentToNodeMetadata.AZURE_LOGIN_PASSWORD; -import static org.jclouds.azurecompute.arm.compute.functions.DeploymentToNodeMetadata.AZURE_LOGIN_USERNAME; +import java.util.Set; -import com.google.common.base.Supplier; -import com.google.common.collect.FluentIterable; +import org.jclouds.azurecompute.arm.domain.ImageReference; import org.jclouds.azurecompute.arm.domain.VMImage; import org.jclouds.collect.Memoized; import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.ImageBuilder; import org.jclouds.compute.domain.OperatingSystem; import org.jclouds.compute.domain.OsFamily; - -import com.google.common.base.Function; -import com.google.inject.Inject; -import org.jclouds.domain.Credentials; import org.jclouds.domain.Location; -import org.jclouds.domain.LoginCredentials; import org.jclouds.location.predicates.LocationPredicates; -import java.util.Set; +import com.google.common.base.Function; +import com.google.common.base.Supplier; +import com.google.common.collect.FluentIterable; +import com.google.inject.Inject; + +import static com.google.common.base.Preconditions.checkNotNull; public class VMImageToImage implements Function { - private static final String UNRECOGNIZED = "UNRECOGNIZED"; - private static final String UBUNTU = "Ubuntu"; - private static final String WINDOWS = "Windows"; - private static final String OPENLOGIC = "openLogic"; - private static final String CENTOS = "CentOS"; - private static final String COREOS = "CoreOS"; - private static final String OPENSUSE = "openSUSE"; - private static final String SUSE = "SUSE"; - - private static final String SQL_SERVER = "SQL Server"; - - private static final String ORACLE_lINUX = "Oracle Linux"; + private static final String SLES = "SLES"; + private static final String ORACLE_lINUX = "Oracle-Linux"; + private static final String RHEL = "RHEL"; private final Supplier> locations; + public static String encodeFieldsToUniqueId(boolean globallyAvailable, String locatioName, ImageReference imageReference){ + return (globallyAvailable ? "global" : locatioName) + "/" + imageReference.publisher() + "/" + imageReference.offer() + "/" + imageReference.sku(); + } + public static String encodeFieldsToUniqueId(VMImage imageReference){ return (imageReference.globallyAvailable() ? "global" : imageReference.location()) + "/" + imageReference.publisher() + "/" + imageReference.offer() + "/" + imageReference.sku(); } 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) { @@ -79,10 +71,10 @@ public class VMImageToImage implements Function { 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) + "/" + @@ -90,7 +82,7 @@ public class VMImageToImage implements Function { 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; } @@ -102,26 +94,21 @@ public class VMImageToImage implements Function { @Override public Image apply(final VMImage image) { - - Credentials credentials = new Credentials(AZURE_LOGIN_USERNAME, AZURE_LOGIN_PASSWORD); 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)) - .defaultCredentials(LoginCredentials.fromCredentials(credentials)); + .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() @@ -130,7 +117,6 @@ public class VMImageToImage implements Function { .status(Image.Status.AVAILABLE) .version(image.sku()) .id(encodeFieldsToUniqueId(image)) - .defaultCredentials(LoginCredentials.fromCredentials(credentials)) .providerId(image.publisher()) .location(image.globallyAvailable() ? null : FluentIterable.from(locations.get()) .firstMatch(LocationPredicates.idEquals(image.location())) @@ -149,11 +135,11 @@ public class VMImageToImage implements Function { final String label = image.offer(); OsFamily family = OsFamily.UNRECOGNIZED; - if (label.contains(CENTOS)) { + if (label.contains(CENTOS) || label.contains(OPENLOGIC)) { family = OsFamily.CENTOS; - } else if (label.contains(OPENLOGIC)) { - family = OsFamily.CENTOS; - } else if (label.contains(SUSE)) { + } else if (label.contains(COREOS)) { + family = OsFamily.COREOS; + } else if (label.contains(SUSE) || label.contains(SLES) || label.contains(OPENSUSE)) { family = OsFamily.SUSE; } else if (label.contains(UBUNTU)) { family = OsFamily.UBUNTU; @@ -161,18 +147,16 @@ public class VMImageToImage implements Function { family = OsFamily.WINDOWS; } else if (label.contains(ORACLE_lINUX)) { family = OsFamily.OEL; + } else if (label.contains(RHEL)) { + 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()); } }; } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VirtualMachineToNodeMetadata.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VirtualMachineToNodeMetadata.java new file mode 100644 index 0000000000..e151a4a17e --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VirtualMachineToNodeMetadata.java @@ -0,0 +1,279 @@ +/* + * 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 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 static org.jclouds.util.Closeables2.closeQuietly; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.annotation.Resource; +import javax.inject.Inject; +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.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.functions.StorageProfileToStorageAccountName; +import org.jclouds.azurecompute.arm.util.BlobHelper; +import org.jclouds.collect.Memoized; +import org.jclouds.compute.domain.Hardware; +import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.NodeMetadataBuilder; +import org.jclouds.compute.functions.GroupNamingConvention; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.domain.Credentials; +import org.jclouds.domain.Location; +import org.jclouds.domain.LoginCredentials; +import org.jclouds.logging.Logger; + +import com.google.common.base.Function; +import com.google.common.base.Functions; +import com.google.common.base.Joiner; +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.base.Splitter; +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + +public class VirtualMachineToNodeMetadata implements Function { + + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + // When using the Deployment API to deploy an ARM template, the deployment + // goes through + // stages. Accepted -> Running -> Succeeded. Only when the deployment has + // SUCCEEDED is + // the resource deployed using the template actually ready. + // + // To get details about the resource(s) deployed via template, one needs to + // query the + // various resources after the deployment has "SUCCEEDED". + private static final Function PROVISIONINGSTATE_TO_NODESTATUS = Functions + .forMap( + ImmutableMap. builder() + .put(VirtualMachineProperties.ProvisioningState.ACCEPTED, NodeMetadata.Status.PENDING) + .put(VirtualMachineProperties.ProvisioningState.READY, NodeMetadata.Status.PENDING) + .put(VirtualMachineProperties.ProvisioningState.CREATING, NodeMetadata.Status.PENDING) + .put(VirtualMachineProperties.ProvisioningState.RUNNING, NodeMetadata.Status.PENDING) + .put(VirtualMachineProperties.ProvisioningState.UPDATING, NodeMetadata.Status.PENDING) + .put(VirtualMachineProperties.ProvisioningState.SUCCEEDED, NodeMetadata.Status.RUNNING) + .put(VirtualMachineProperties.ProvisioningState.DELETED, NodeMetadata.Status.TERMINATED) + .put(VirtualMachineProperties.ProvisioningState.CANCELED, NodeMetadata.Status.TERMINATED) + .put(VirtualMachineProperties.ProvisioningState.FAILED, NodeMetadata.Status.ERROR) + .put(VirtualMachineProperties.ProvisioningState.UNRECOGNIZED, NodeMetadata.Status.UNRECOGNIZED) + .build(), NodeMetadata.Status.UNRECOGNIZED); + + private static final Function POWERSTATE_TO_NODESTATUS = Functions + .forMap( + ImmutableMap. builder() + .put(PowerState.RUNNING, NodeMetadata.Status.RUNNING) + .put(PowerState.STOPPED, NodeMetadata.Status.SUSPENDED) + .put(PowerState.UNRECOGNIZED, NodeMetadata.Status.UNRECOGNIZED).build(), + NodeMetadata.Status.UNRECOGNIZED); + + private final String azureGroup; + private final AzureComputeApi api; + private final GroupNamingConvention nodeNamingConvention; + private final Supplier> images; + private final Supplier> locations; + private final Supplier> hardwares; + private final Map credentialStore; + private final Function vmImageToImge; + private final StorageProfileToStorageAccountName storageProfileToStorageAccountName; + + @Inject + VirtualMachineToNodeMetadata(AzureComputeApi api, GroupNamingConvention.Factory namingConvention, + Supplier> images, Supplier> hardwares, + @Memoized Supplier> locations, Map credentialStore, + final AzureComputeConstants azureComputeConstants, Function vmImageToImge, + StorageProfileToStorageAccountName storageProfileToStorageAccountName) { + this.api = api; + this.nodeNamingConvention = namingConvention.createWithoutPrefix(); + this.images = checkNotNull(images, "images cannot be null"); + this.locations = checkNotNull(locations, "locations cannot be null"); + this.hardwares = checkNotNull(hardwares, "hardwares cannot be null"); + this.credentialStore = credentialStore; + this.azureGroup = azureComputeConstants.azureResourceGroup(); + this.vmImageToImge = vmImageToImge; + this.storageProfileToStorageAccountName = storageProfileToStorageAccountName; + } + + @Override + public NodeMetadata apply(VirtualMachine virtualMachine) { + NodeMetadataBuilder builder = new NodeMetadataBuilder(); + builder.id(virtualMachine.name()); + builder.providerId(virtualMachine.id()); + builder.name(virtualMachine.name()); + builder.hostname(virtualMachine.name()); + String group = this.nodeNamingConvention.extractGroup(virtualMachine.name()); + builder.group(group); + + ProvisioningState provisioningState = virtualMachine.properties().provisioningState(); + if (ProvisioningState.SUCCEEDED.equals(provisioningState)) { + // If the provisioning succeeded, we need to query the *real* status of + // the VM + VirtualMachineInstance instanceDetails = api.getVirtualMachineApi(azureGroup).getInstanceDetails( + virtualMachine.name()); + builder.status(POWERSTATE_TO_NODESTATUS.apply(instanceDetails.powerState())); + builder.backendStatus(Joiner.on(',').join( + transform(instanceDetails.statuses(), new Function() { + @Override + public String apply(VirtualMachineStatus input) { + return input.code(); + } + }))); + } else { + builder.status(PROVISIONINGSTATE_TO_NODESTATUS.apply(provisioningState)); + builder.backendStatus(provisioningState.name()); + } + + Credentials credentials = credentialStore.get("node#" + virtualMachine.name()); + builder.credentials(LoginCredentials.fromCredentials(credentials)); + + builder.publicAddresses(getPublicIpAddresses(virtualMachine.properties().networkProfile().networkInterfaces())); + builder.privateAddresses(getPrivateIpAddresses(virtualMachine.properties().networkProfile().networkInterfaces())); + + if (virtualMachine.tags() != null) { + Map userMetaData = virtualMachine.tags(); + builder.userMetadata(userMetaData); + builder.tags(Splitter.on(",").split(userMetaData.get("tags"))); + } + String locationName = virtualMachine.location(); + builder.location(getLocation(locationName)); + + Optional image = findImage(virtualMachine.properties().storageProfile(), locationName); + if (image.isPresent()) { + builder.imageId(image.get().getId()); + builder.operatingSystem(image.get().getOperatingSystem()); + } else { + logger.info(">> image with id %s for virtualmachine %s was not found. " + + "This might be because the image that was used to create the virtualmachine has a new id.", + virtualMachine.id(), virtualMachine.id()); + } + + builder.hardware(getHardware(virtualMachine.properties().hardwareProfile().vmSize())); + + return builder.build(); + } + + private Iterable getPrivateIpAddresses(List idReferences) { + List privateIpAddresses = Lists.newArrayList(); + for (IdReference networkInterfaceCardIdReference : idReferences) { + NetworkInterfaceCard networkInterfaceCard = getNetworkInterfaceCard(networkInterfaceCardIdReference); + for (IpConfiguration ipConfiguration : networkInterfaceCard.properties().ipConfigurations()) { + privateIpAddresses.add(ipConfiguration.properties().privateIPAddress()); + } + } + return privateIpAddresses; + } + + private NetworkInterfaceCard getNetworkInterfaceCard(IdReference networkInterfaceCardIdReference) { + Iterables.get(Splitter.on("/").split(networkInterfaceCardIdReference.id()), 2); + String resourceGroup = Iterables.get(Splitter.on("/").split(networkInterfaceCardIdReference.id()), 4); + String nicName = Iterables.getLast(Splitter.on("/").split(networkInterfaceCardIdReference.id())); + return api.getNetworkInterfaceCardApi(resourceGroup).get(nicName); + + } + + private Iterable getPublicIpAddresses(List idReferences) { + List publicIpAddresses = Lists.newArrayList(); + for (IdReference networkInterfaceCardIdReference : idReferences) { + NetworkInterfaceCard networkInterfaceCard = getNetworkInterfaceCard(networkInterfaceCardIdReference); + String resourceGroup = Iterables.get(Splitter.on("/").split(networkInterfaceCardIdReference.id()), 4); + for (IpConfiguration ipConfiguration : networkInterfaceCard.properties().ipConfigurations()) { + if (ipConfiguration.properties().publicIPAddress() != null) { + String publicIpId = ipConfiguration.properties().publicIPAddress().id(); + publicIpAddresses.add(api.getPublicIPAddressApi(resourceGroup) + .get(Iterables.getLast(Splitter.on("/").split(publicIpId))).properties().ipAddress()); + } + } + } + return publicIpAddresses; + } + + protected Location getLocation(final String locationName) { + return find(locations.get(), new Predicate() { + @Override + public boolean apply(Location location) { + return locationName != null && locationName.equals(location.getId()); + } + }, null); + } + + protected Optional findImage(final StorageProfile storageProfile, String locatioName) { + if (storageProfile.imageReference() != null) { + return Optional.fromNullable(images.get().get( + encodeFieldsToUniqueId(false, locatioName, storageProfile.imageReference()))); + } else { + String storageAccountName = storageProfileToStorageAccountName.apply(storageProfile); + StorageServiceKeys keys = api.getStorageAccountApi(azureGroup).getKeys(storageAccountName); + BlobHelper blobHelper = new BlobHelper(storageAccountName, keys.key1()); + + try { + // Custom image. Let's find it by uri + List customImagesInStorage = blobHelper.getImages(CONTAINER_NAME, azureGroup, CUSTOM_IMAGE_OFFER, + locatioName); + Optional customImage = tryFind(customImagesInStorage, new Predicate() { + @Override + public boolean apply(VMImage input) { + return input.vhd1().equals(storageProfile.osDisk().image().uri()); + } + }); + + return customImage.isPresent() ? Optional.of(vmImageToImge.apply(customImage.get())) : Optional + . absent(); + } finally { + closeQuietly(blobHelper); + } + } + } + + protected Hardware getHardware(final String vmSize) { + return Iterables.find(hardwares.get().values(), new Predicate() { + @Override + public boolean apply(Hardware input) { + return input.getId().equals(vmSize); + } + }); + } + +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/AzureTemplateOptions.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/AzureTemplateOptions.java index c5267b1dbe..c71a7daba0 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/AzureTemplateOptions.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/AzureTemplateOptions.java @@ -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); + } } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/predicates/IsDeploymentInRegions.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/predicates/IsDeploymentInRegions.java index 57a0678b82..66590e1ed1 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/predicates/IsDeploymentInRegions.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/predicates/IsDeploymentInRegions.java @@ -40,6 +40,7 @@ public class IsDeploymentInRegions implements Predicate { @Override public boolean apply(Deployment deployment) { + if (deployment.properties() == null || deployment.properties().parameters() == null || deployment.properties().parameters().get("location") == null) return false; Value locationValue = deployment.properties().parameters().get("location"); return regionIds.get().contains(locationValue.value()); } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/AzurePopulateDefaultLoginCredentialsForImageStrategy.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/AzurePopulateDefaultLoginCredentialsForImageStrategy.java deleted file mode 100644 index 55d1a3ce37..0000000000 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/AzurePopulateDefaultLoginCredentialsForImageStrategy.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jclouds.azurecompute.arm.compute.strategy; - -import org.jclouds.compute.domain.internal.ImageImpl; -import org.jclouds.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy; -import org.jclouds.domain.Credentials; -import org.jclouds.domain.LoginCredentials; - -import static org.jclouds.azurecompute.arm.compute.functions.DeploymentToNodeMetadata.AZURE_LOGIN_PASSWORD; -import static org.jclouds.azurecompute.arm.compute.functions.DeploymentToNodeMetadata.AZURE_LOGIN_USERNAME; - -public class AzurePopulateDefaultLoginCredentialsForImageStrategy implements PopulateDefaultLoginCredentialsForImageStrategy { - @Override - public LoginCredentials apply(Object o) { - ImageImpl node = (ImageImpl)o; - String username = AZURE_LOGIN_USERNAME; - String password = AZURE_LOGIN_PASSWORD; - if (username == null) { - username = "jclouds"; - } - if (password == null) { - password = "Password1!"; - } - Credentials creds = new Credentials(username, password); - LoginCredentials credentials = LoginCredentials.fromCredentials(creds); - return credentials; - } -} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourceGroupThenCreateNodes.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourceGroupThenCreateNodes.java index 468b87c6f2..99528fdcbe 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourceGroupThenCreateNodes.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourceGroupThenCreateNodes.java @@ -17,26 +17,36 @@ 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; import java.util.Set; +import java.util.UUID; import javax.annotation.Resource; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; -import com.google.common.collect.ImmutableMap; import org.jclouds.Constants; +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.VMImage; +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; @@ -45,9 +55,11 @@ import org.jclouds.compute.strategy.CreateNodeWithGroupEncodedIntoName; import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap; import org.jclouds.compute.strategy.ListNodesStrategy; import org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet; -import org.jclouds.azurecompute.arm.AzureComputeApi; -import org.jclouds.azurecompute.arm.domain.VirtualNetwork; 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; @@ -81,7 +93,13 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco public Map> execute(String group, int count, Template template, Set goodNodes, Map badNodes, Multimap customizationResponses) { - + // If there is a script to be run on the node and public key + // authentication has been configured, warn users if the private key + // is not present + if (hasRunScriptWithKeyAuthAndNoPrivateKey(template)) { + logger.warn(">> a runScript was configured but no SSH key has been provided. " + + "Authentication will delegate to the ssh-agent"); + } String azureGroupName = this.azureComputeConstants.azureResourceGroup(); AzureTemplateOptions options = template.getOptions().as(AzureTemplateOptions.class); @@ -91,7 +109,7 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco final String location = template.getLocation().getId(); if (resourceGroup == null){ - final Map tags = ImmutableMap.of("description", "jClouds managed VMs"); + final Map tags = ImmutableMap.of("description", "jclouds managed VMs"); resourceGroupApi.create(azureGroupName, location, tags).name(); } @@ -104,7 +122,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> responses = super.execute(group, count, template, goodNodes, badNodes, customizationResponses); @@ -135,6 +156,70 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco options.virtualNetworkName(virtualNetworkName); options.subnetId(subnet.id()); + } + private static boolean hasRunScriptWithKeyAuthAndNoPrivateKey(Template template) { + return template.getOptions().getRunScript() != null && template.getOptions().getPublicKey() != null + && !template.getOptions().hasLoginPrivateKeyOption(); + } + + public StorageService getOrCreateStorageService(String name, String resourceGroupName, String locationName, Image image) { + String storageAccountName = null; + VMImage imageRef = decodeFieldsFromUniqueId(image.getId()); + if (imageRef.custom()) { + storageAccountName = imageRef.storage(); + } + + 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("jclouds", + name), ImmutableMap.of("accountType", StorageService.AccountType.Standard_LRS.toString())); + boolean starageAccountCreated = retry(new Predicate() { + @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 + checkState(starageAccountCreated, "Storage account %s was not created in the configured timeout", + storageAccountName); + return api.getStorageAccountApi(resourceGroupName).get(storageAccountName); + } + + /** + * 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 random = UUID.randomUUID().toString().substring(0, 4); + String storageAccountName = new StringBuilder().append(name).append(random).toString(); + String sanitizedStorageAccountName = storageAccountName.replaceAll("[^a-z0-9]", ""); + int nameLength = sanitizedStorageAccountName.length(); + if (nameLength >= 3 && nameLength <= 24) { + return sanitizedStorageAccountName; + } + + if (nameLength > 24) { + sanitizedStorageAccountName = shorten(storageAccountName, random); + } + return sanitizedStorageAccountName; + } + + 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); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeHttpApiModule.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeHttpApiModule.java index bd1750f6ed..991c73883f 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeHttpApiModule.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeHttpApiModule.java @@ -18,7 +18,6 @@ package org.jclouds.azurecompute.arm.config; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.handlers.AzureComputeErrorHandler; -import org.jclouds.azurecompute.arm.util.DeploymentTemplateBuilder; import org.jclouds.http.HttpErrorHandler; import org.jclouds.http.annotation.ClientError; import org.jclouds.http.annotation.Redirection; @@ -30,7 +29,6 @@ import org.jclouds.rest.ConfiguresHttpApi; import org.jclouds.rest.config.HttpApiModule; import com.google.inject.Scopes; -import com.google.inject.assistedinject.FactoryModuleBuilder; @ConfiguresHttpApi public class AzureComputeHttpApiModule extends HttpApiModule { @@ -51,7 +49,6 @@ public class AzureComputeHttpApiModule extends HttpApiModule { @Override protected void configure() { - install(new FactoryModuleBuilder().build(DeploymentTemplateBuilder.Factory.class)); super.configure(); bind(OAuthScopes.class).toInstance(OAuthScopes.NoScopes.create()); } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeProperties.java index e5ef5cd561..8f945d94e2 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeProperties.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeProperties.java @@ -17,10 +17,13 @@ package org.jclouds.azurecompute.arm.config; /** - * Configuration properties and constants used in Azure Resource Manager connections. + * Configuration properties and constants used in Azure Resource Manager + * connections. */ 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 +34,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"; @@ -47,4 +48,6 @@ public class AzureComputeProperties { public static final String DEFAULT_DATADISKSIZE = "jclouds.azurecompute.arm.datadisksize"; + public static final String API_VERSION_PREFIX = "jclouds.azurecompute.arm.apiversion."; + } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMDeployment.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMDeployment.java index 948e69bced..99edc5c448 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMDeployment.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMDeployment.java @@ -16,43 +16,29 @@ */ package org.jclouds.azurecompute.arm.domain; -import com.google.auto.value.AutoValue; +import java.util.List; + import org.jclouds.javax.annotation.Nullable; -import java.util.List; -import java.util.Map; +import com.google.auto.value.AutoValue; @AutoValue public abstract class VMDeployment { - public abstract Deployment deployment(); - + public abstract String deploymentId(); + + @Nullable + public abstract VirtualMachine virtualMachine(); + @Nullable public abstract List ipAddressList(); - @Nullable - public abstract VirtualMachineInstance vm(); - - @Nullable - public abstract VirtualMachine virtualMachine(); - @Nullable public abstract List networkInterfaceCards(); - @Nullable - public abstract Map userMetaData(); - - @Nullable - public abstract Iterable tags(); - - public static VMDeployment create(Deployment deployment) { - return create(deployment, null, null, null, null, null, null); - } - - public static VMDeployment create(Deployment deployment, List ipAddressList, - VirtualMachineInstance vm, VirtualMachine virtualMachine, - List networkInterfaceCards, Map userMetaData, - Iterable tags) { - return new AutoValue_VMDeployment(deployment, ipAddressList, vm, virtualMachine, networkInterfaceCards, userMetaData, tags); + public static VMDeployment create(String deploymentId, VirtualMachine virtualMachine, + List ipAddressList, + List networkInterfaceCards) { + return new AutoValue_VMDeployment(deploymentId, virtualMachine, ipAddressList, networkInterfaceCards); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java index c83eafe22e..e4f2301168 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java @@ -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(); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachine.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachine.java index 3013543979..10fa231c85 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachine.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachine.java @@ -16,12 +16,13 @@ */ package org.jclouds.azurecompute.arm.domain; -import com.google.auto.value.AutoValue; -import com.google.common.collect.ImmutableMap; +import java.util.Map; + import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; -import java.util.Map; +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableMap; /** * A virtual machine that is valid for your subscription. diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineInstance.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineInstance.java index b0ed6d5ea3..1c11e4d0f3 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineInstance.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineInstance.java @@ -16,13 +16,23 @@ */ package org.jclouds.azurecompute.arm.domain; -import com.google.auto.value.AutoValue; -import com.google.common.collect.ImmutableList; +import static com.google.common.collect.Iterables.filter; +import static com.google.common.collect.Iterables.getFirst; +import static com.google.common.collect.Iterables.transform; +import static org.jclouds.util.Predicates2.startsWith; + +import java.util.Date; import java.util.List; + +import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance.VirtualMachineStatus.PowerState; +import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties.ProvisioningState; +import org.jclouds.azurecompute.arm.util.GetEnumValue; import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; -import java.util.Date; +import com.google.auto.value.AutoValue; +import com.google.common.base.Function; +import com.google.common.collect.ImmutableList; /** * A virtual machine instance view that is valid for your subscription. @@ -30,8 +40,21 @@ import java.util.Date; @AutoValue public abstract class VirtualMachineInstance { - @AutoValue + @com.google.auto.value.AutoValue public abstract static class VirtualMachineStatus { + + public static final String PROVISIONING_STATE_PREFIX = "ProvisioningState/"; + public static final String POWER_STATE_PREFIX = "PowerState/"; + + public enum PowerState { + RUNNING, + STOPPED, + UNRECOGNIZED; + + public static PowerState fromValue(final String text) { + return (PowerState) GetEnumValue.fromValueOrDefault(text, PowerState.UNRECOGNIZED); + } + } @Nullable public abstract String code(); @@ -61,6 +84,26 @@ public abstract class VirtualMachineInstance { @Nullable public abstract List statuses(); + + public ProvisioningState provisioningState() { + return ProvisioningState.fromValue(firstStatus(VirtualMachineStatus.PROVISIONING_STATE_PREFIX)); + } + + public PowerState powerState() { + return PowerState.fromValue(firstStatus(VirtualMachineStatus.POWER_STATE_PREFIX)); + } + + private String firstStatus(final String type) { + return getFirst(transform(filter(transform(statuses(), new Function() { + @Override public String apply(VirtualMachineStatus input) { + return input.code(); + } + }), startsWith(type)), new Function() { + @Override public String apply(String input) { + return input.substring(type.length()); + } + }), null); + } @SerializedNames({"platformUpdateDomain", "platformFaultDomain", "statuses"}) diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineProperties.java index 73afd14678..eb9520aa33 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineProperties.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineProperties.java @@ -16,16 +16,35 @@ */ package org.jclouds.azurecompute.arm.domain; -import com.google.auto.value.AutoValue; +import org.jclouds.azurecompute.arm.util.GetEnumValue; import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; +import com.google.auto.value.AutoValue; + /** * A virtual machine properties for the virtual machine. */ @AutoValue public abstract class VirtualMachineProperties { + public enum ProvisioningState { + ACCEPTED, + CREATING, + READY, + CANCELED, + FAILED, + DELETED, + SUCCEEDED, + RUNNING, + UPDATING, + UNRECOGNIZED; + + public static ProvisioningState fromValue(final String text) { + return (ProvisioningState) GetEnumValue.fromValueOrDefault(text, ProvisioningState.UNRECOGNIZED); + } + } + /** * The id of the virtual machine. */ @@ -78,7 +97,7 @@ public abstract class VirtualMachineProperties { * The provisioning state of the VM */ @Nullable - public abstract String provisioningState(); + public abstract ProvisioningState provisioningState(); @SerializedNames({"vmId", "licenseType", "availabilitySet", "hardwareProfile", "storageProfile", "osProfile", "networkProfile", "diagnosticsProfile", "provisioningState"}) @@ -90,7 +109,7 @@ public abstract class VirtualMachineProperties { final OSProfile osProfile, final NetworkProfile networkProfile, final DiagnosticsProfile diagnosticsProfile, - final String provisioningState) { + final ProvisioningState provisioningState) { return builder() .vmId(vmId) .licenseType(licenseType) @@ -126,7 +145,7 @@ public abstract class VirtualMachineProperties { public abstract Builder diagnosticsProfile(DiagnosticsProfile diagnosticsProfile); - public abstract Builder provisioningState(String provisioningState); + public abstract Builder provisioningState(ProvisioningState provisioningState); public abstract VirtualMachineProperties build(); } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/DeploymentApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/DeploymentApi.java index 33c929a67c..8d446a5d58 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/DeploymentApi.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/DeploymentApi.java @@ -34,12 +34,12 @@ import org.jclouds.Fallbacks; import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; import org.jclouds.Fallbacks.NullOnNotFoundOr404; import org.jclouds.azurecompute.arm.domain.Deployment; +import org.jclouds.azurecompute.arm.filters.ApiVersionFilter; import org.jclouds.azurecompute.arm.functions.URIParser; import org.jclouds.oauth.v2.filters.OAuthFilter; import org.jclouds.rest.annotations.Fallback; import org.jclouds.rest.annotations.Payload; import org.jclouds.rest.annotations.PayloadParam; -import org.jclouds.rest.annotations.QueryParams; import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.ResponseParser; import org.jclouds.rest.annotations.SelectJson; @@ -50,8 +50,7 @@ import org.jclouds.rest.annotations.SelectJson; * - get information about deployment */ @Path("/resourcegroups/{resourcegroup}/providers/microsoft.resources/deployments") -@QueryParams(keys = "api-version", values = "2016-02-01") -@RequestFilters(OAuthFilter.class) +@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) @Consumes(MediaType.APPLICATION_JSON) public interface DeploymentApi { diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/JobApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/JobApi.java index f2858d9ca4..3c3bab9bf3 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/JobApi.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/JobApi.java @@ -18,19 +18,20 @@ package org.jclouds.azurecompute.arm.features; import java.io.Closeable; import java.net.URI; import java.util.List; + import javax.ws.rs.Consumes; -import javax.ws.rs.core.MediaType; import javax.ws.rs.GET; +import javax.ws.rs.core.MediaType; import org.jclouds.Fallbacks; import org.jclouds.azurecompute.arm.domain.ResourceDefinition; +import org.jclouds.azurecompute.arm.functions.ParseJobStatus; +import org.jclouds.azurecompute.arm.functions.ParseJobStatus.JobStatus; import org.jclouds.oauth.v2.filters.OAuthFilter; import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.rest.annotations.Fallback; import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.ResponseParser; -import org.jclouds.azurecompute.arm.functions.ParseJobStatus; -import org.jclouds.azurecompute.arm.functions.ParseJobStatus.JobStatus; import org.jclouds.rest.annotations.SelectJson; /** diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/LocationApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/LocationApi.java index 8f31d31626..257293ceae 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/LocationApi.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/LocationApi.java @@ -27,11 +27,11 @@ import javax.ws.rs.core.MediaType; import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; import org.jclouds.azurecompute.arm.domain.Location; +import org.jclouds.azurecompute.arm.filters.ApiVersionFilter; import org.jclouds.oauth.v2.filters.OAuthFilter; -import org.jclouds.rest.annotations.QueryParams; +import org.jclouds.rest.annotations.Fallback; import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.SelectJson; -import org.jclouds.rest.annotations.Fallback; /** * This Azure Resource Manager API provides all of the locations that are available for resource providers @@ -40,8 +40,7 @@ import org.jclouds.rest.annotations.Fallback; * @see docs */ @Path("/locations") -@RequestFilters(OAuthFilter.class) -@QueryParams(keys = "api-version", values = "2015-11-01") +@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public interface LocationApi { diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApi.java index 2f19996901..c135e9ebe2 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApi.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApi.java @@ -16,20 +16,9 @@ */ package org.jclouds.azurecompute.arm.features; -import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; -import org.jclouds.Fallbacks.NullOnNotFoundOr404; -import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; -import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCardProperties; -import org.jclouds.azurecompute.arm.functions.URIParser; -import org.jclouds.oauth.v2.filters.OAuthFilter; -import org.jclouds.rest.annotations.Fallback; -import org.jclouds.rest.annotations.MapBinder; -import org.jclouds.rest.annotations.PayloadParam; -import org.jclouds.rest.annotations.QueryParams; -import org.jclouds.rest.annotations.RequestFilters; -import org.jclouds.rest.annotations.ResponseParser; -import org.jclouds.rest.annotations.SelectJson; -import org.jclouds.rest.binders.BindToJsonPayload; +import java.net.URI; +import java.util.List; +import java.util.Map; import javax.inject.Named; import javax.ws.rs.Consumes; @@ -39,15 +28,25 @@ import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.core.MediaType; -import java.util.List; -import java.util.Map; -import java.net.URI; + +import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; +import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCardProperties; +import org.jclouds.azurecompute.arm.filters.ApiVersionFilter; +import org.jclouds.azurecompute.arm.functions.URIParser; +import org.jclouds.oauth.v2.filters.OAuthFilter; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.MapBinder; +import org.jclouds.rest.annotations.PayloadParam; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SelectJson; +import org.jclouds.rest.binders.BindToJsonPayload; @Path("/resourcegroups/{resourcegroup}/providers/Microsoft.Network/networkInterfaces") -@QueryParams(keys = "api-version", values = "2015-06-15") -@RequestFilters(OAuthFilter.class) +@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) @Consumes(MediaType.APPLICATION_JSON) - public interface NetworkInterfaceCardApi { @Named("networkinterfacecard:list") diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApi.java index e6b310d973..ba4c2cd35a 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApi.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApi.java @@ -16,40 +16,38 @@ */ package org.jclouds.azurecompute.arm.features; -import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; -import org.jclouds.Fallbacks.NullOnNotFoundOr404; -import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; -import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroupProperties; -import org.jclouds.azurecompute.arm.functions.URIParser; -import org.jclouds.javax.annotation.Nullable; -import org.jclouds.oauth.v2.filters.OAuthFilter; - -import org.jclouds.rest.annotations.RequestFilters; -import org.jclouds.rest.annotations.QueryParams; -import org.jclouds.rest.annotations.SelectJson; -import org.jclouds.rest.annotations.Fallback; -import org.jclouds.rest.annotations.PayloadParam; -import org.jclouds.rest.annotations.ResponseParser; -import org.jclouds.rest.annotations.MapBinder; -import org.jclouds.rest.binders.BindToJsonPayload; - -import javax.inject.Named; -import javax.ws.rs.Produces; -import javax.ws.rs.Path; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.DELETE; -import javax.ws.rs.PUT; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.MediaType; import java.net.URI; import java.util.List; import java.util.Map; -@Path("/resourcegroups/{resourcegroup}/providers/Microsoft.Network/networkSecurityGroups") +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; -@QueryParams(keys = "api-version", values = "2016-03-30") -@RequestFilters(OAuthFilter.class) +import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroupProperties; +import org.jclouds.azurecompute.arm.filters.ApiVersionFilter; +import org.jclouds.azurecompute.arm.functions.URIParser; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.oauth.v2.filters.OAuthFilter; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.MapBinder; +import org.jclouds.rest.annotations.PayloadParam; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SelectJson; +import org.jclouds.rest.binders.BindToJsonPayload; + +@Path("/resourcegroups/{resourcegroup}/providers/Microsoft.Network/networkSecurityGroups") +@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) @Consumes(MediaType.APPLICATION_JSON) public interface NetworkSecurityGroupApi { @@ -72,9 +70,8 @@ public interface NetworkSecurityGroupApi { @MapBinder(BindToJsonPayload.class) @Produces(MediaType.APPLICATION_JSON) NetworkSecurityGroup createOrUpdate(@PathParam("networksecuritygroupname") String nsgName, - @PayloadParam("location") String location, - @Nullable @PayloadParam("tags") Map tags, - @PayloadParam("properties")NetworkSecurityGroupProperties properties); + @PayloadParam("location") String location, @Nullable @PayloadParam("tags") Map tags, + @PayloadParam("properties") NetworkSecurityGroupProperties properties); @Named("networksecuritygroup:get") @Path("/{networksecuritygroupname}") @@ -82,4 +79,3 @@ public interface NetworkSecurityGroupApi { @Fallback(NullOnNotFoundOr404.class) NetworkSecurityGroup get(@PathParam("networksecuritygroupname") String nsgName); } - diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/NetworkSecurityRuleApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/NetworkSecurityRuleApi.java index 2edd3df560..8def4e3cd1 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/NetworkSecurityRuleApi.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/NetworkSecurityRuleApi.java @@ -16,38 +16,36 @@ */ package org.jclouds.azurecompute.arm.features; +import java.net.URI; +import java.util.List; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; import org.jclouds.Fallbacks.NullOnNotFoundOr404; import org.jclouds.azurecompute.arm.domain.NetworkSecurityRule; import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties; +import org.jclouds.azurecompute.arm.filters.ApiVersionFilter; import org.jclouds.azurecompute.arm.functions.URIParser; import org.jclouds.oauth.v2.filters.OAuthFilter; - -import org.jclouds.rest.annotations.RequestFilters; -import org.jclouds.rest.annotations.QueryParams; -import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.annotations.Fallback; -import org.jclouds.rest.annotations.PayloadParam; -import org.jclouds.rest.annotations.ResponseParser; import org.jclouds.rest.annotations.MapBinder; +import org.jclouds.rest.annotations.PayloadParam; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.binders.BindToJsonPayload; -import javax.inject.Named; -import javax.ws.rs.Produces; -import javax.ws.rs.Path; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.DELETE; -import javax.ws.rs.PUT; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.MediaType; -import java.util.List; -import java.net.URI; - @Path("/resourcegroups/{resourcegroup}/providers/Microsoft.Network/networkSecurityGroups/{networksecuritygroup}") - -@QueryParams(keys = "api-version", values = "2016-03-30") -@RequestFilters(OAuthFilter.class) +@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) @Consumes(MediaType.APPLICATION_JSON) public interface NetworkSecurityRuleApi { @Named("networksecurityrule:createOrUpdate") diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/OSImageApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/OSImageApi.java index 96dce6b92e..c8fb3f3aa3 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/OSImageApi.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/OSImageApi.java @@ -31,17 +31,16 @@ import org.jclouds.azurecompute.arm.domain.Offer; import org.jclouds.azurecompute.arm.domain.Publisher; import org.jclouds.azurecompute.arm.domain.SKU; import org.jclouds.azurecompute.arm.domain.Version; +import org.jclouds.azurecompute.arm.filters.ApiVersionFilter; import org.jclouds.oauth.v2.filters.OAuthFilter; import org.jclouds.rest.annotations.Fallback; -import org.jclouds.rest.annotations.QueryParams; import org.jclouds.rest.annotations.RequestFilters; /** * The Azure Resource Management API includes operations for managing the OS images in your subscription. */ @Path("/providers/Microsoft.Compute/locations/{location}") -@RequestFilters(OAuthFilter.class) -@QueryParams(keys = "api-version", values = "2015-06-15") +@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) @Consumes(APPLICATION_JSON) public interface OSImageApi { diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApi.java index 2e19fe2d04..26937535ff 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApi.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApi.java @@ -16,20 +16,8 @@ */ package org.jclouds.azurecompute.arm.features; -import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; -import org.jclouds.Fallbacks.NullOnNotFoundOr404; -import org.jclouds.azurecompute.arm.domain.PublicIPAddress; -import org.jclouds.azurecompute.arm.domain.PublicIPAddressProperties; -import org.jclouds.azurecompute.arm.functions.FalseOn204; -import org.jclouds.oauth.v2.filters.OAuthFilter; -import org.jclouds.rest.annotations.Fallback; -import org.jclouds.rest.annotations.MapBinder; -import org.jclouds.rest.annotations.PayloadParam; -import org.jclouds.rest.annotations.QueryParams; -import org.jclouds.rest.annotations.RequestFilters; -import org.jclouds.rest.annotations.ResponseParser; -import org.jclouds.rest.annotations.SelectJson; -import org.jclouds.rest.binders.BindToJsonPayload; +import java.util.List; +import java.util.Map; import javax.inject.Named; import javax.ws.rs.Consumes; @@ -39,14 +27,25 @@ import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.core.MediaType; -import java.util.List; -import java.util.Map; + +import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.azurecompute.arm.domain.PublicIPAddress; +import org.jclouds.azurecompute.arm.domain.PublicIPAddressProperties; +import org.jclouds.azurecompute.arm.filters.ApiVersionFilter; +import org.jclouds.azurecompute.arm.functions.FalseOn204; +import org.jclouds.oauth.v2.filters.OAuthFilter; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.MapBinder; +import org.jclouds.rest.annotations.PayloadParam; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SelectJson; +import org.jclouds.rest.binders.BindToJsonPayload; @Path("/resourcegroups/{resourcegroup}/providers/Microsoft.Network/publicIPAddresses") -@QueryParams(keys = "api-version", values = "2015-06-15") -@RequestFilters(OAuthFilter.class) +@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) @Consumes(MediaType.APPLICATION_JSON) - public interface PublicIPAddressApi { @Named("publicipaddress:list") diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ResourceGroupApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ResourceGroupApi.java index 1ad47d941c..6f718a59e3 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ResourceGroupApi.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ResourceGroupApi.java @@ -19,32 +19,31 @@ import java.io.Closeable; import java.net.URI; import java.util.List; import java.util.Map; + import javax.inject.Named; import javax.ws.rs.Consumes; -import javax.ws.rs.core.MediaType; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; import org.jclouds.Fallbacks.NullOnNotFoundOr404; import org.jclouds.azurecompute.arm.domain.ResourceGroup; +import org.jclouds.azurecompute.arm.filters.ApiVersionFilter; +import org.jclouds.azurecompute.arm.functions.URIParser; import org.jclouds.javax.annotation.Nullable; import org.jclouds.oauth.v2.filters.OAuthFilter; -import org.jclouds.rest.annotations.QueryParams; -import org.jclouds.rest.annotations.RequestFilters; -import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.annotations.Fallback; import org.jclouds.rest.annotations.MapBinder; -import org.jclouds.rest.annotations.PayloadParam; import org.jclouds.rest.annotations.PATCH; +import org.jclouds.rest.annotations.PayloadParam; +import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.ResponseParser; -import org.jclouds.azurecompute.arm.functions.URIParser; - - +import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.binders.BindToJsonPayload; /** @@ -53,9 +52,7 @@ import org.jclouds.rest.binders.BindToJsonPayload; * @see docs */ @Path("/resourcegroups") - -@QueryParams(keys = "api-version", values = "2015-01-01") -@RequestFilters(OAuthFilter.class) +@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) @Consumes(MediaType.APPLICATION_JSON) public interface ResourceGroupApi extends Closeable{ diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ResourceProviderApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ResourceProviderApi.java index e3d38b8ebd..a25e2a507e 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ResourceProviderApi.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ResourceProviderApi.java @@ -17,14 +17,8 @@ package org.jclouds.azurecompute.arm.features; -import org.jclouds.Fallbacks.NullOnNotFoundOr404; -import org.jclouds.azurecompute.arm.domain.ResourceProviderMetaData; -import org.jclouds.javax.annotation.Nullable; -import org.jclouds.oauth.v2.filters.OAuthFilter; -import org.jclouds.rest.annotations.Fallback; -import org.jclouds.rest.annotations.QueryParams; -import org.jclouds.rest.annotations.RequestFilters; -import org.jclouds.rest.annotations.SelectJson; +import java.io.Closeable; +import java.util.List; import javax.inject.Named; import javax.ws.rs.Consumes; @@ -32,8 +26,15 @@ import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.core.MediaType; -import java.io.Closeable; -import java.util.List; + +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.azurecompute.arm.domain.ResourceProviderMetaData; +import org.jclouds.azurecompute.arm.filters.ApiVersionFilter; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.oauth.v2.filters.OAuthFilter; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.SelectJson; /** * The Azure Resource Provider API provides information about a resource provider and its supported resource types. @@ -42,8 +43,7 @@ import java.util.List; */ @Path("/providers") -@QueryParams(keys = "api-version", values = "2015-01-01") -@RequestFilters(OAuthFilter.class) +@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) @Consumes(MediaType.APPLICATION_JSON) public interface ResourceProviderApi extends Closeable { diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/StorageAccountApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/StorageAccountApi.java index fd75fcab37..5d2e06c6db 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/StorageAccountApi.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/StorageAccountApi.java @@ -16,15 +16,19 @@ */ package org.jclouds.azurecompute.arm.features; +import java.net.URI; +import java.util.List; +import java.util.Map; + import javax.inject.Named; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; import javax.ws.rs.Consumes; -import javax.ws.rs.PUT; -import javax.ws.rs.POST; import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.jclouds.Fallbacks; @@ -32,35 +36,28 @@ import org.jclouds.azurecompute.arm.domain.Availability; import org.jclouds.azurecompute.arm.domain.StorageService; import org.jclouds.azurecompute.arm.domain.StorageServiceKeys; import org.jclouds.azurecompute.arm.domain.StorageServiceUpdateParams; +import org.jclouds.azurecompute.arm.filters.ApiVersionFilter; import org.jclouds.azurecompute.arm.functions.FalseOn204; import org.jclouds.azurecompute.arm.functions.URIParser; import org.jclouds.javax.annotation.Nullable; import org.jclouds.oauth.v2.filters.OAuthFilter; import org.jclouds.rest.annotations.Fallback; -import org.jclouds.rest.annotations.QueryParams; -import org.jclouds.rest.annotations.RequestFilters; -import org.jclouds.rest.annotations.SelectJson; -import org.jclouds.rest.annotations.Payload; -import org.jclouds.rest.annotations.PATCH; -import org.jclouds.rest.annotations.ResponseParser; -import org.jclouds.rest.annotations.PayloadParam; import org.jclouds.rest.annotations.MapBinder; +import org.jclouds.rest.annotations.PATCH; +import org.jclouds.rest.annotations.Payload; +import org.jclouds.rest.annotations.PayloadParam; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.binders.BindToJsonPayload; -import java.util.List; -import java.util.Map; -import java.net.URI; - -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.STORAGE_API_VERSION; - /** * The Azure Resource Management API includes operations for managing the storage accounts in your subscription. * * @see docs */ @Path("/") -@RequestFilters(OAuthFilter.class) -@QueryParams(keys = "api-version", values = STORAGE_API_VERSION) +@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) @Consumes(MediaType.APPLICATION_JSON) public interface StorageAccountApi { diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/SubnetApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/SubnetApi.java index 1ac38d8b99..8f30d6cb08 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/SubnetApi.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/SubnetApi.java @@ -16,20 +16,7 @@ */ package org.jclouds.azurecompute.arm.features; -import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; -import org.jclouds.Fallbacks.NullOnNotFoundOr404; -import org.jclouds.azurecompute.arm.domain.Subnet; -import org.jclouds.azurecompute.arm.functions.FalseOn204; -import org.jclouds.oauth.v2.filters.OAuthFilter; -import org.jclouds.rest.binders.BindToJsonPayload; - -import org.jclouds.rest.annotations.Fallback; -import org.jclouds.rest.annotations.QueryParams; -import org.jclouds.rest.annotations.RequestFilters; -import org.jclouds.rest.annotations.SelectJson; -import org.jclouds.rest.annotations.ResponseParser; -import org.jclouds.rest.annotations.PayloadParam; -import org.jclouds.rest.annotations.MapBinder; +import java.util.List; import javax.inject.Named; import javax.ws.rs.Consumes; @@ -39,12 +26,24 @@ import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.core.MediaType; -import java.util.List; + +import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.azurecompute.arm.domain.Subnet; +import org.jclouds.azurecompute.arm.filters.ApiVersionFilter; +import org.jclouds.azurecompute.arm.functions.FalseOn204; +import org.jclouds.oauth.v2.filters.OAuthFilter; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.MapBinder; +import org.jclouds.rest.annotations.PayloadParam; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SelectJson; +import org.jclouds.rest.binders.BindToJsonPayload; @Path("/resourcegroups/{resourcegroup}/providers/Microsoft.Network/virtualNetworks/{virtualnetwork}/subnets") -@QueryParams(keys = "api-version", values = "2015-06-15") -@RequestFilters(OAuthFilter.class) +@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) @Consumes(MediaType.APPLICATION_JSON) public interface SubnetApi { diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VMSizeApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VMSizeApi.java index 345e08c40e..b5917ce400 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VMSizeApi.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VMSizeApi.java @@ -16,24 +16,24 @@ */ package org.jclouds.azurecompute.arm.features; -import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; -import org.jclouds.azurecompute.arm.domain.VMSize; -import org.jclouds.oauth.v2.filters.OAuthFilter; -import org.jclouds.rest.annotations.Fallback; -import org.jclouds.rest.annotations.QueryParams; -import org.jclouds.rest.annotations.RequestFilters; -import org.jclouds.rest.annotations.SelectJson; +import java.util.List; import javax.inject.Named; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.core.MediaType; -import java.util.List; + +import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; +import org.jclouds.azurecompute.arm.domain.VMSize; +import org.jclouds.azurecompute.arm.filters.ApiVersionFilter; +import org.jclouds.oauth.v2.filters.OAuthFilter; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.SelectJson; @Path("/providers/Microsoft.Compute/locations/{location}/vmSizes") -@QueryParams(keys = "api-version", values = "2015-06-15") -@RequestFilters(OAuthFilter.class) +@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) @Consumes(MediaType.APPLICATION_JSON) public interface VMSizeApi { diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualMachineApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualMachineApi.java index 14f3c70332..2dd6d342cc 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualMachineApi.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualMachineApi.java @@ -16,10 +16,25 @@ */ package org.jclouds.azurecompute.arm.features; +import java.net.URI; +import java.util.List; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + import org.jclouds.Fallbacks; import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance; import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties; +import org.jclouds.azurecompute.arm.filters.ApiVersionFilter; import org.jclouds.azurecompute.arm.functions.URIParser; import org.jclouds.oauth.v2.filters.OAuthFilter; import org.jclouds.rest.annotations.Fallback; @@ -32,27 +47,13 @@ import org.jclouds.rest.annotations.ResponseParser; import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.binders.BindToJsonPayload; -import javax.inject.Named; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; -import java.net.URI; -import java.util.List; - /** * The Virtual Machine API includes operations for managing the virtual machines in your subscription. * * @see docs */ @Path("/resourceGroups/{resourceGroup}/providers/Microsoft.Compute/virtualMachines") -@RequestFilters(OAuthFilter.class) -@QueryParams(keys = "api-version", values = "2015-06-15") +@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) @Consumes(MediaType.APPLICATION_JSON) public interface VirtualMachineApi { @@ -66,14 +67,14 @@ public interface VirtualMachineApi { VirtualMachine get(@PathParam("name") String name); /** - * The Get Virtual Machine details + * Get information about the model view and instance view of a virtual machine: */ @Named("GetVirtualMachineInstance") @GET @Path("/{name}/instanceView") @Fallback(Fallbacks.NullOnNotFoundOr404.class) VirtualMachineInstance getInstanceDetails(@PathParam("name") String name); - + /** * The Create Virtual Machine */ diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApi.java index 0acbdeeca1..1e657f39cb 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApi.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApi.java @@ -15,22 +15,7 @@ * limitations under the License. */ package org.jclouds.azurecompute.arm.features; -import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; -import org.jclouds.Fallbacks.NullOnNotFoundOr404; - -import org.jclouds.azurecompute.arm.domain.VirtualNetwork; - -import org.jclouds.azurecompute.arm.functions.FalseOn204; -import org.jclouds.oauth.v2.filters.OAuthFilter; - -import org.jclouds.rest.annotations.Fallback; -import org.jclouds.rest.annotations.QueryParams; -import org.jclouds.rest.annotations.RequestFilters; -import org.jclouds.rest.annotations.SelectJson; -import org.jclouds.rest.annotations.ResponseParser; -import org.jclouds.rest.annotations.PayloadParam; -import org.jclouds.rest.annotations.MapBinder; -import org.jclouds.rest.binders.BindToJsonPayload; +import java.util.List; import javax.inject.Named; import javax.ws.rs.Consumes; @@ -40,11 +25,23 @@ import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.core.MediaType; -import java.util.List; + +import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.azurecompute.arm.domain.VirtualNetwork; +import org.jclouds.azurecompute.arm.filters.ApiVersionFilter; +import org.jclouds.azurecompute.arm.functions.FalseOn204; +import org.jclouds.oauth.v2.filters.OAuthFilter; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.MapBinder; +import org.jclouds.rest.annotations.PayloadParam; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SelectJson; +import org.jclouds.rest.binders.BindToJsonPayload; @Path("/resourcegroups/{resourcegroup}/providers/Microsoft.Network/virtualNetworks") -@QueryParams(keys = "api-version", values = "2015-06-15") -@RequestFilters(OAuthFilter.class) +@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) @Consumes(MediaType.APPLICATION_JSON) public interface VirtualNetworkApi { diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/filters/ApiVersionFilter.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/filters/ApiVersionFilter.java new file mode 100644 index 0000000000..904c2e8bf8 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/filters/ApiVersionFilter.java @@ -0,0 +1,90 @@ +/* + * 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.filters; + +import static com.google.common.base.Preconditions.checkArgument; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.API_VERSION_PREFIX; +import static org.jclouds.util.Maps2.transformKeys; +import static org.jclouds.util.Predicates2.startsWith; + +import java.util.Map; + +import javax.inject.Inject; + +import org.jclouds.http.HttpException; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpRequestFilter; +import org.jclouds.rest.config.InvocationConfig; +import org.jclouds.rest.internal.GeneratedHttpRequest; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.reflect.Invokable; + +/** + * Allow users to customize the api versions for each method call. + *

+ * In Azure ARM, each method may have its own api version. This filter allows to + * configure the versions of each method, so there is no need to change the code + * when Azure deprecates old versions. + */ +public class ApiVersionFilter implements HttpRequestFilter { + + private final InvocationConfig config; + private final Map versions; + + @Inject + ApiVersionFilter(InvocationConfig config, Function, Map> filterStringsBoundByName) { + this.config = config; + this.versions = versions(filterStringsBoundByName); + } + + @Override + public HttpRequest filter(HttpRequest request) throws HttpException { + checkArgument(request instanceof GeneratedHttpRequest, + "This filter can only be applied to GeneratedHttpRequest objects"); + GeneratedHttpRequest generatedRequest = (GeneratedHttpRequest) request; + + // Look if there is a custom api version for the current method + String commandName = config.getCommandName(generatedRequest.getInvocation()); + String customApiVersion = versions.get(commandName); + + if (customApiVersion == null) { + // No custom config for the specific method. Let's look for custom + // config for the class + Invokable invoked = generatedRequest.getInvocation().getInvokable(); + String className = invoked.getOwnerType().getRawType().getSimpleName(); + customApiVersion = versions.get(className); + } + + if (customApiVersion != null) { + return request.toBuilder().replaceQueryParam("api-version", customApiVersion).build(); + } + + return request; + } + + private static Map versions(Function, Map> filterStringsBoundByName) { + Map stringBoundWithApiVersionPrefix = filterStringsBoundByName + .apply(startsWith(API_VERSION_PREFIX)); + return transformKeys(stringBoundWithApiVersionPrefix, new Function() { + public String apply(String input) { + return input.replaceFirst(API_VERSION_PREFIX, ""); + } + }); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/CleanupResources.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/CleanupResources.java index 6970887886..39cc32c23d 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/CleanupResources.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/CleanupResources.java @@ -14,127 +14,163 @@ * 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 static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED; +import static org.jclouds.util.Closeables2.closeQuietly; + +import java.net.URI; +import java.util.List; +import java.util.Map; import javax.annotation.Resource; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; -import com.google.common.base.Predicate; import org.jclouds.azurecompute.arm.AzureComputeApi; -import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule; -import org.jclouds.azurecompute.arm.domain.Deployment; +import org.jclouds.azurecompute.arm.domain.IdReference; +import org.jclouds.azurecompute.arm.domain.IpConfiguration; import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; -import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; -import org.jclouds.azurecompute.arm.domain.PublicIPAddress; +import org.jclouds.azurecompute.arm.domain.ResourceGroup; +import org.jclouds.azurecompute.arm.domain.StorageServiceKeys; import org.jclouds.azurecompute.arm.domain.VirtualMachine; +import org.jclouds.azurecompute.arm.util.BlobHelper; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.logging.Logger; import com.google.common.base.Function; - -import java.net.URI; +import com.google.common.base.Predicate; +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; @Singleton public class CleanupResources implements Function { - private final AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants; @Resource @Named(ComputeServiceConstants.COMPUTE_LOGGER) protected Logger logger = Logger.NULL; protected final AzureComputeApi api; - private Predicate nodeTerminated; - private Predicate resourceDeleted; + private final Predicate resourceDeleted; + private final StorageProfileToStorageAccountName storageProfileToStorageAccountName; @Inject - public CleanupResources(AzureComputeApi azureComputeApi, - AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants, - @Named(TIMEOUT_NODE_TERMINATED) Predicate nodeTerminated, - @Named(TIMEOUT_RESOURCE_DELETED) Predicate resourceDeleted) { - this.azureComputeConstants = azureComputeConstants; + CleanupResources(AzureComputeApi azureComputeApi, @Named(TIMEOUT_RESOURCE_DELETED) Predicate resourceDeleted, + StorageProfileToStorageAccountName storageProfileToStorageAccountName) { this.api = azureComputeApi; - this.nodeTerminated = nodeTerminated; this.resourceDeleted = resourceDeleted; + this.storageProfileToStorageAccountName = storageProfileToStorageAccountName; } @Override - public Boolean apply(String id) { + public Boolean apply(final String id) { + logger.debug(">> destroying %s ...", id); - logger.debug("Destroying %s ...", id); - String storageAccountName = id.replaceAll("[^A-Za-z0-9 ]", "") + "stor"; - String group = azureComputeConstants.azureResourceGroup(); + Map resourceGroupNamesAndVirtualMachines = getResourceGroupNamesAndVirtualMachines(id); + if (resourceGroupNamesAndVirtualMachines.isEmpty()) + return true; - VirtualMachine vm = api.getVirtualMachineApi(group).get(id); - if (vm != null) { - URI uri = api.getVirtualMachineApi(group).delete(id); - if (uri != null) { - boolean jobDone = nodeTerminated.apply(uri); - boolean storageAcctDeleteStatus = false; - boolean deploymentDeleteStatus = false; + 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 (jobDone) { - Deployment deployment = api.getDeploymentApi(group).get(id); - if (deployment != null) { - uri = api.getDeploymentApi(group).delete(id); - jobDone = resourceDeleted.apply(uri); - if (jobDone) { - deploymentDeleteStatus = true; - } - } else { - deploymentDeleteStatus = true; - } - NetworkInterfaceCard nic = api.getNetworkInterfaceCardApi(group).get(id + "nic"); - if (nic != null) { - uri = api.getNetworkInterfaceCardApi(group).delete(id + "nic"); - if (uri != null) { - jobDone = resourceDeleted.apply(uri); - if (jobDone) { - boolean ipDeleteStatus = false; - PublicIPAddress ip = api.getPublicIPAddressApi(group).get(id + "publicip"); - if (ip != null) { - ipDeleteStatus = api.getPublicIPAddressApi(group).delete(id + "publicip"); - } else { - ipDeleteStatus = true; - } + boolean vmDeleted = deleteVirtualMachine(group, virtualMachine); + + // We don't delete the network here, as it is global to the resource + // group. It will be deleted when the resource group is deleted - // Get NSG - boolean nsgDeleteStatus = false; - NetworkSecurityGroup nsg = api.getNetworkSecurityGroupApi(group).get(id + "nsg"); - if (nsg != null) { - uri = api.getNetworkSecurityGroupApi(group).delete(id + "nsg"); - jobDone = resourceDeleted.apply(uri); - if (jobDone) { - nsgDeleteStatus = true; + for (String nicName : getNetworkCardInterfaceNames(virtualMachine)) { + NetworkInterfaceCard nic = api.getNetworkInterfaceCardApi(group).get(nicName); + Iterable publicIps = getPublicIps(group, nic); - } - } - else { - nsgDeleteStatus = true; - } + logger.debug(">> destroying nic %s...", nicName); + URI nicDeletionURI = api.getNetworkInterfaceCardApi(group).delete(nicName); + resourceDeleted.apply(nicDeletionURI); - return deploymentDeleteStatus && storageAcctDeleteStatus && ipDeleteStatus && nsgDeleteStatus; - } else { - return false; - } - } else { - return false; - } - } else { - return false; - } - } else { - return false; - } - } else { - return false; + for (String publicIp : publicIps) { + logger.debug(">> deleting public ip nic %s...", publicIp); + api.getPublicIPAddressApi(group).delete(publicIp); } - } else { - return false; + } + + String storageAccountName = storageProfileToStorageAccountName.apply(virtualMachine.properties().storageProfile()); + StorageServiceKeys keys = api.getStorageAccountApi(group).getKeys(storageAccountName); + + // Remove the virtual machine files + logger.debug(">> deleting virtual machine disk storage..."); + BlobHelper blobHelper = new BlobHelper(storageAccountName, keys.key1()); + try { + blobHelper.deleteContainerIfExists("vhds"); + + if (!blobHelper.customImageExists()) { + 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!"); + } + } finally { + closeQuietly(blobHelper); + } + + deleteResourceGroupIfEmpty(group); + + return vmDeleted; + } + + 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)); } } + + private Iterable getPublicIps(String group, NetworkInterfaceCard nic) { + return transform( + filter(transform(nic.properties().ipConfigurations(), new Function() { + @Override + public IdReference apply(IpConfiguration input) { + return input.properties().publicIPAddress(); + } + }), notNull()), new Function() { + @Override + public String apply(IdReference input) { + return Iterables.getLast(Splitter.on("/").split(input.id())); + } + }); + } + + private List getNetworkCardInterfaceNames(VirtualMachine virtualMachine) { + List nics = Lists.newArrayList(); + for (IdReference idReference : virtualMachine.properties().networkProfile().networkInterfaces()) { + nics.add(Iterables.getLast(Splitter.on("/").split(idReference.id()))); + } + return nics; + } + + private boolean deleteVirtualMachine(String group, VirtualMachine virtualMachine) { + return resourceDeleted.apply(api.getVirtualMachineApi(group).delete(virtualMachine.name())); + } + + private Map getResourceGroupNamesAndVirtualMachines(String id) { + for (ResourceGroup resourceGroup : api.getResourceGroupApi().list()) { + String group = resourceGroup.name(); + VirtualMachine virtualMachine = api.getVirtualMachineApi(group).get(id); + if (virtualMachine != null) { + return ImmutableMap.of(group, virtualMachine); + } + } + return Maps.newHashMap(); + } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/StorageProfileToStorageAccountName.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/StorageProfileToStorageAccountName.java new file mode 100644 index 0000000000..f624886d66 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/StorageProfileToStorageAccountName.java @@ -0,0 +1,38 @@ +/* + * 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.functions; + +import java.net.URI; + +import org.jclouds.azurecompute.arm.domain.StorageProfile; + +import com.google.common.base.Function; +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; + +/** + * Returns the storage account name for a given storage profile. + */ +public class StorageProfileToStorageAccountName implements Function { + + @Override + public String apply(StorageProfile input) { + String storageAccountNameURI = input.osDisk().vhd().uri(); + return Iterables.get(Splitter.on(".").split(URI.create(storageAccountNameURI).getHost()), 0); + } + +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/BlobHelper.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/BlobHelper.java index f5bfc758af..b42ea5e9d0 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/BlobHelper.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/BlobHelper.java @@ -16,76 +16,68 @@ */ package org.jclouds.azurecompute.arm.util; +import static org.jclouds.util.Closeables2.closeQuietly; + +import java.io.Closeable; +import java.io.IOException; 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 class BlobHelper implements Closeable { - public static void deleteContainerIfExists(String storage, String key, String containerName) { - final AzureBlobClient azureBlob = ContextBuilder.newBuilder("azureblob") - .credentials(storage, key) - .buildApi(AzureBlobClient.class); + private final String storageAccount; + private final AzureBlobClient azureBlob; - try { - azureBlob.deleteContainer(containerName); - } - finally { - Closeables2.closeQuietly(azureBlob); - } + public BlobHelper(String storageAccount, String key) { + this.storageAccount = storageAccount; + this.azureBlob = ContextBuilder.newBuilder("azureblob").credentials(storageAccount, key) + .buildApi(AzureBlobClient.class); } - public static boolean customImageExists(String storage, String key) { - final AzureBlobClient azureBlob = ContextBuilder.newBuilder("azureblob") - .credentials(storage, key) - .buildApi(AzureBlobClient.class); - - try { - return azureBlob.containerExists("system"); - } - finally { - Closeables2.closeQuietly(azureBlob); - } + @Override + public void close() throws IOException { + closeQuietly(azureBlob); } - public static List 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 void deleteContainerIfExists(String containerName) { + azureBlob.deleteContainer(containerName); + } + public boolean hasContainers() { + return !azureBlob.listContainers().isEmpty(); + } + public boolean customImageExists() { + return azureBlob.containerExists("system"); + } + + public List getImages(String containerName, String group, String offer, String location) { List list = new ArrayList(); - try { - BoundedSet containerList = azureBlob.listContainers(); - for (ContainerProperties props : containerList) { - if (props.getName().equals("system")) { - ListBlobsResponse blobList = azureBlob.listBlobs("system"); - String osDisk = ""; - String dataDisk = ""; - for (BlobProperties blob : blobList) { - String name = blob.getName(); + ContainerProperties systemContainer = azureBlob.getContainerProperties("system"); + if (systemContainer != null) { + ListBlobsResponse blobList = azureBlob.listBlobs(systemContainer.getName()); + for (BlobProperties blob : blobList) { + String name = blob.getName(); - if (dataDisk.length() == 0) dataDisk = name.substring(1 + name.lastIndexOf('/')); - else if (osDisk.length() == 0) osDisk = name.substring(1 + name.lastIndexOf('/')); - } - final VMImage ref = VMImage.create(group, storageAccountName, osDisk, dataDisk, "test-create-image", "custom", location); - list.add(ref); + if (name.contains("-osDisk")) { + String imageName = name.substring(name.lastIndexOf('/') + 1, name.indexOf("-osDisk")); + String imageUrl = blob.getUrl().toString(); + + list.add(VMImage.customImage().group(group).storage(storageAccount).vhd1(imageUrl).name(imageName) + .offer(offer).location(location).build()); } } } - finally { - Closeables2.closeQuietly(azureBlob); - } + return list; } + } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/DeploymentTemplateBuilder.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/DeploymentTemplateBuilder.java deleted file mode 100644 index e5b0a43f82..0000000000 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/DeploymentTemplateBuilder.java +++ /dev/null @@ -1,573 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jclouds.azurecompute.arm.util; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule; -import org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageExtension; -import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; -import org.jclouds.azurecompute.arm.domain.DataDisk; -import org.jclouds.azurecompute.arm.domain.DeploymentBody; -import org.jclouds.azurecompute.arm.domain.DeploymentProperties; -import org.jclouds.azurecompute.arm.domain.DeploymentTemplate; -import org.jclouds.azurecompute.arm.domain.DiagnosticsProfile; -import org.jclouds.azurecompute.arm.domain.DnsSettings; -import org.jclouds.azurecompute.arm.domain.HardwareProfile; -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.IpConfigurationProperties; -import org.jclouds.azurecompute.arm.domain.KeyVaultReference; -import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCardProperties; -import org.jclouds.azurecompute.arm.domain.NetworkProfile; -import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroupProperties; -import org.jclouds.azurecompute.arm.domain.NetworkSecurityRule; -import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties; -import org.jclouds.azurecompute.arm.domain.OSDisk; -import org.jclouds.azurecompute.arm.domain.OSProfile; -import org.jclouds.azurecompute.arm.domain.PublicIPAddressProperties; -import org.jclouds.azurecompute.arm.domain.ResourceDefinition; -import org.jclouds.azurecompute.arm.domain.StorageProfile; -import org.jclouds.azurecompute.arm.domain.StorageService; -import org.jclouds.azurecompute.arm.domain.StorageService.StorageServiceProperties; -import org.jclouds.azurecompute.arm.domain.TemplateParameterType; -import org.jclouds.azurecompute.arm.domain.VHD; -import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties; -import org.jclouds.compute.domain.Template; -import org.jclouds.json.Json; -import org.jclouds.predicates.Validator; -import org.jclouds.predicates.validators.DnsNameValidator; - -import com.google.common.base.Joiner; -import com.google.common.base.Preconditions; -import com.google.common.base.Strings; -import com.google.common.collect.Lists; -import com.google.inject.Inject; -import com.google.inject.assistedinject.Assisted; - -import static com.google.common.io.BaseEncoding.base64; -import static org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageExtension.CUSTOM_IMAGE_PREFIX; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.STORAGE_API_VERSION; - -public class DeploymentTemplateBuilder { - public interface Factory { - DeploymentTemplateBuilder create(@Assisted("group") String group, @Assisted("name") String name, Template template); - } - - private final String name; - private final String azureGroup; - private final String group; - private final Template template; - private final Json json; - - private AzureTemplateOptions options; - private Iterable tags; - private Map userMetaData; - private List resources; - private Map variables; - private static String loginUser; - private static String loginPassword; - private String location; - private AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants; - - private static final String DEPLOYMENT_MODE = "Incremental"; - - @Inject - DeploymentTemplateBuilder(Json json, @Assisted("group") String group, @Assisted("name") String name, @Assisted Template template, - final AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants) { - this.name = name; - this.group = group; - this.template = template; - this.options = template.getOptions().as(AzureTemplateOptions.class); - this.tags = template.getOptions().getTags(); - this.userMetaData = template.getOptions().getUserMetadata(); - this.variables = new HashMap(); - this.resources = new ArrayList(); - this.location = template.getLocation().getId(); - this.json = json; - - this.azureComputeConstants = azureComputeConstants; - this.azureGroup = this.azureComputeConstants.azureResourceGroup(); - - String[] defaultLogin = this.azureComputeConstants.azureDefaultImageLogin().split(":"); - String defaultUser = null; - String defaultPassword = null; - - if (defaultLogin.length == 2) { - defaultUser = defaultLogin[0].trim(); - defaultPassword = defaultLogin[1].trim(); - } - - loginUser = options.getLoginUser() == null ? defaultUser : options.getLoginUser(); - loginPassword = options.getLoginPassword() == null ? defaultPassword : options.getLoginPassword(); - } - - public static String getLoginUserUsername() { - return loginUser; - } - - public static String getLoginPassword() { - return loginPassword; - } - - public Template getTemplate() { - return template; - } - - public DeploymentBody getDeploymentTemplate() { - - addStorageResource(); - addPublicIpAddress(); - addNetworkSecurityGroup(); - addNetworkInterfaceCard(); - addVirtualMachine(); - - - DeploymentTemplate.TemplateParameters templateParameters = null; - DeploymentTemplate.Parameters parameters = null; - - if (keyVaultInUse()){ - String[] keyVaultInfo = options.getKeyVaultIdAndSecret().split(":"); - Preconditions.checkArgument(keyVaultInfo.length == 2); - String vaultId = keyVaultInfo[0].trim(); - String secretName = keyVaultInfo[1].trim(); - - templateParameters = DeploymentTemplate.TemplateParameters.create(TemplateParameterType.create("securestring")); - parameters = DeploymentTemplate.Parameters.create(KeyVaultReference.create(KeyVaultReference.Reference.create(IdReference.create(vaultId), secretName))); - } else { - templateParameters = DeploymentTemplate.TemplateParameters.create(null); - parameters = DeploymentTemplate.Parameters.create(null); - } - - - DeploymentTemplate template = DeploymentTemplate.builder() - .schema("https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#") - .contentVersion("1.0.0.0") - .resources(resources) - .variables(variables) - .parameters(templateParameters) - .build(); - - DeploymentBody body = DeploymentBody.create(template, DEPLOYMENT_MODE, parameters); - - return body; - } - - public String getDeploymentTemplateJson(DeploymentProperties properties) { - return json.toJson(properties); - } - - private void addStorageResource() { - String storageAccountName = null; - - String imageName = template.getImage().getName(); - if (imageName.startsWith(CUSTOM_IMAGE_PREFIX)) { - storageAccountName = template.getImage().getVersion(); - } - - if (Strings.isNullOrEmpty(storageAccountName)) { - storageAccountName = generateStorageAccountName(name); - } - - Validator validator = new DnsNameValidator(3, 24); - validator.validate(storageAccountName); - - variables.put("storageAccountName", storageAccountName); - - ResourceDefinition storageAccount = ResourceDefinition.builder() - .name("[variables('storageAccountName')]") - .type("Microsoft.Storage/storageAccounts") - .location(location) - .apiVersion(STORAGE_API_VERSION) - .properties( - StorageServiceProperties.builder() - .accountType(StorageService.AccountType.Standard_LRS) - .build() - ) - .build(); - - resources.add(storageAccount); - } - - private void addPublicIpAddress() { - String publicIPAddressName = name + "publicip"; - String dnsLabelPrefix = options.getDNSLabelPrefix(); - - PublicIPAddressProperties.Builder properties = PublicIPAddressProperties.builder(); - - if (!Strings.isNullOrEmpty(dnsLabelPrefix)) { - properties.dnsSettings(DnsSettings.builder().domainNameLabel(dnsLabelPrefix).build()); - variables.put("dnsLabelPrefix", dnsLabelPrefix); - } - - properties.publicIPAllocationMethod("Dynamic"); - variables.put("publicIPAddressName", publicIPAddressName); - variables.put("publicIPAddressReference", "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]"); - - ResourceDefinition publicIpAddress = ResourceDefinition.builder() - .name("[variables('publicIPAddressName')]") - .type("Microsoft.Network/publicIPAddresses") - .location(location) - .apiVersion(STORAGE_API_VERSION) - .properties(properties.build()) - .build(); - - resources.add(publicIpAddress); - } - - private void addNetworkInterfaceCard() { - - List ipConfigurations = new ArrayList(); - - String ipConfigurationName = name + "ipconfig"; - String subnetId = options.getSubnetId(); - String vnetName = options.getVirtualNetworkName(); - - variables.put("ipConfigurationName", ipConfigurationName); - variables.put("subnetReference", subnetId); - - IpConfiguration ipConfig = IpConfiguration.create(ipConfigurationName, null, null, null, - IpConfigurationProperties.builder() - .privateIPAllocationMethod("Dynamic") - .publicIPAddress(IdReference.create("[variables('publicIPAddressReference')]")) - .subnet(IdReference.create("[variables('subnetReference')]")) - .build()); - - ipConfigurations.add(ipConfig); - - // Check to see if we have defined a network security group - IdReference networkSecurityGroup = null; - int ports[] = options.getInboundPorts(); - if ((ports != null) && (ports.length > 0)) { - networkSecurityGroup = IdReference.create("[variables('networkSecurityGroupNameReference')]"); - } - - ArrayList depends = new ArrayList(Arrays.asList("[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]")); - - NetworkInterfaceCardProperties.Builder networkInterfaceCardPropertiesBuilder = NetworkInterfaceCardProperties.builder(); - networkInterfaceCardPropertiesBuilder.ipConfigurations(ipConfigurations); - if (networkSecurityGroup != null) { - networkInterfaceCardPropertiesBuilder.networkSecurityGroup(networkSecurityGroup); - depends.add("[concat('Microsoft.Network/networkSecurityGroups/', variables('networkSecurityGroupName'))]"); - } - NetworkInterfaceCardProperties networkInterfaceCardProperties = networkInterfaceCardPropertiesBuilder.build(); - - String networkInterfaceCardName = name + "nic"; - variables.put("networkInterfaceCardName", networkInterfaceCardName); - variables.put("networkInterfaceCardReference", "[resourceId('Microsoft.Network/networkInterfaces',variables('networkInterfaceCardName'))]"); - - ResourceDefinition networkInterfaceCard = ResourceDefinition.builder() - .name("[variables('networkInterfaceCardName')]") - .type("Microsoft.Network/networkInterfaces") - .location(location) - .apiVersion(STORAGE_API_VERSION) - .dependsOn(depends) - .properties(networkInterfaceCardProperties) - .build(); - - resources.add(networkInterfaceCard); - } - - private void addNetworkSecurityGroup() { - int inboundPorts[] = options.getInboundPorts(); - if ((inboundPorts != null) && (inboundPorts.length > 0)) { - variables.put("networkSecurityGroupName", name + "nsg"); - variables.put("networkSecurityGroupNameReference", "[resourceId('Microsoft.Network/networkSecurityGroups',variables('networkSecurityGroupName'))]"); - - List portRanges = simplifyPorts(inboundPorts); - - List rules = new ArrayList(); - int priority = 1234; - for (String portRange : portRanges) { - NetworkSecurityRuleProperties ruleProperties = NetworkSecurityRuleProperties.builder() - .description("default-allow-port-" + portRange) - .protocol(NetworkSecurityRuleProperties.Protocol.All) - .access(NetworkSecurityRuleProperties.Access.Allow) - .sourcePortRange("*") - .destinationPortRange(portRange) - .sourceAddressPrefix("*") - .destinationAddressPrefix("*") - .priority(priority) - .direction(NetworkSecurityRuleProperties.Direction.Inbound) - .build(); - - NetworkSecurityRule networkSecurityRule = NetworkSecurityRule.create( - "default-allow-port-" + portRange, - null, - null, - ruleProperties); - - rules.add(networkSecurityRule); - priority++; - } - - NetworkSecurityGroupProperties networkSecurityGroupProperties = NetworkSecurityGroupProperties.builder() - .securityRules(rules) - .build(); - - ResourceDefinition networkSecurityGroup = ResourceDefinition.builder() - .name("[variables('networkSecurityGroupName')]") - .type("Microsoft.Network/networkSecurityGroups").location(location) - .apiVersion(STORAGE_API_VERSION) - .properties(networkSecurityGroupProperties) - .build(); - resources.add(networkSecurityGroup); - } - - } - - /** - * Helper function for simplifying an array of ports to a list of ranges as list of strings - * @param ports array of int - * @return list of strings representing ranges - */ - public static List simplifyPorts(int[] ports) { - Preconditions.checkArgument(ports != null && ports.length != 0); - ArrayList output = new ArrayList(); - Arrays.sort(ports); - - int range_start = ports[0]; - int range_end = ports[0]; - for (int i = 1; i < ports.length; i++) { - if ((ports[i - 1] == ports[i] - 1) || (ports[i - 1] == ports[i])){ - // Range continues. - range_end = ports[i]; - } - else { - // Range ends. - output.add(formatRange(range_start, range_end)); - range_start = ports[i]; - range_end = ports[i]; - } - } - // Make sure we get the last range. - output.add(formatRange(range_start, range_end)); - return output; - } - - private static String formatRange(int start, int finish) { - if (start == finish){ - return Integer.toString(start); - } - else { - return String.format("%s-%s", Integer.toString(start), Integer.toString(finish)); - } - } - - private void addVirtualMachine() { - //Build OS Profile - final String computerName = name + "pc"; - - variables.put("loginUser", loginUser); - OSProfile.Builder profileBuilder = OSProfile.builder() - .adminUsername(loginUser) - .computerName(computerName); - - profileBuilder.adminPassword(loginPassword); - //boolean usePublicKey = options.getPublicKey() != null; - - if (keyVaultInUse()) { - OSProfile.LinuxConfiguration configuration = OSProfile.LinuxConfiguration.create("false", - OSProfile.LinuxConfiguration.SSH.create(Arrays.asList( - OSProfile.LinuxConfiguration.SSH.SSHPublicKey.create( - "[concat('/home/',variables('loginUser'),'/.ssh/authorized_keys')]", - "[parameters('publicKeyFromAzureKeyVault')]" - )) - )); - profileBuilder.linuxConfiguration(configuration); - } - - if (!Strings.isNullOrEmpty(options.getCustomData())){ - String encodedCustomData = base64().encode(options.getCustomData().getBytes()); - profileBuilder.customData(encodedCustomData); - } - - OSProfile osProfile = profileBuilder.build(); - - //Build OsDisk - final String storageAccountContainerName = name + "vhds"; - variables.put("storageAccountContainerName", storageAccountContainerName); - - final String osDiskName = name + "osdisk"; - variables.put("osDiskName", osDiskName); - - boolean usingMarketplaceImage = true; - String cusotomImageUri = ""; - - // Handle custom image case if description starts with CUSTOM_IMAGE_PREFIX - String vhd1 = template.getImage().getProviderId(); - String description = template.getImage().getDescription(); - if (description.substring(0, CUSTOM_IMAGE_PREFIX.length()).equals(CUSTOM_IMAGE_PREFIX)) { - String storageName = template.getImage().getVersion(); - cusotomImageUri = vhd1; - cusotomImageUri = "https://" + storageName + ".blob.core.windows.net/system/Microsoft.Compute/Images/" + AzureComputeImageExtension.CONTAINER_NAME + "/" + cusotomImageUri; - } - - if (!cusotomImageUri.isEmpty()) { - usingMarketplaceImage = false; - } - - OSDisk osDisk = getOsDisk("[concat('http://',variables('storageAccountName'),'.blob.core.windows.net/',variables('storageAccountContainerName'),'/',variables('osDiskName'),'.vhd')]", cusotomImageUri); - - //Create Data Disk(s) and add to list - final String dataDiskName = name + "datadisk"; - variables.put("dataDiskName", dataDiskName); - - List dataDisks = new ArrayList(); - DataDisk dataDisk = DataDisk.builder() - .name("[variables('dataDiskName')]") - .diskSizeGB(azureComputeConstants.azureDefaultDataDiskSizeProperty()) - .lun(0) - .vhd( - VHD.create("[concat('http://',variables('storageAccountName'),'.blob.core.windows.net/',variables('storageAccountContainerName'),'/',variables('dataDiskName'),'.vhd')]") - ) - .createOption("Empty") - .build(); - - dataDisks.add(dataDisk); - - //Create Storage Profile - StorageProfile.Builder storageProfileBuilder = StorageProfile.builder() - .osDisk(osDisk) - .dataDisks(dataDisks); - - if (usingMarketplaceImage) { - //Build Image Reference if marketplace image is used - ImageReference imageReference = getImageReference(template.getImage().getProviderId(), - template.getImage().getName(), - template.getImage().getVersion()); - - storageProfileBuilder.imageReference(imageReference); - } - StorageProfile storageProfile = storageProfileBuilder.build(); - - - //Create Network Profile for this VM (links to network interface cards) - NetworkProfile networkProfile = NetworkProfile.create( - Arrays.asList( - IdReference.create("[variables('networkInterfaceCardReference')]") - )); - - //Boot Diagnostics - DiagnosticsProfile diagnosticsProfile = DiagnosticsProfile.create( - DiagnosticsProfile.BootDiagnostics.builder() - .enabled(true) - .storageUri("[concat('http://',variables('storageAccountName'),'.blob.core.windows.net')]") - .build()); - - //Build VirtualMachine properties based on above properties. - final String vmSize = template.getHardware().getId(); - HardwareProfile hw = HardwareProfile.create(vmSize); - - VirtualMachineProperties properties = VirtualMachineProperties.builder() - .hardwareProfile(hw) - .osProfile(osProfile) - .storageProfile(storageProfile) - .networkProfile(networkProfile) - .diagnosticsProfile(diagnosticsProfile) - .build(); - - - String tagString = Joiner.on(",").join(Lists.newArrayList(tags)); - if (tagString.isEmpty()) - tagString = "jclouds"; - userMetaData.put("tags", tagString); - - variables.put("virtualMachineName", name); - ResourceDefinition virtualMachine = ResourceDefinition.builder() - .name("[variables('virtualMachineName')]") - .type("Microsoft.Compute/virtualMachines") - .location(location) - .apiVersion("2015-06-15") - .dependsOn(Arrays.asList("[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]", - "[concat('Microsoft.Network/networkInterfaces/', variables('networkInterfaceCardName'))]")) - .tags(userMetaData) - .properties(properties) - .build(); - - resources.add(virtualMachine); - } - - - private ImageReference getImageReference(String publisher, String offer, String sku) { - return ImageReference.builder() - .publisher(publisher) - .offer(offer) - .sku(sku) - .version("latest") - .build(); - - } - - private OSDisk getOsDisk(String vhdUri, String imageUri) { - OSDisk.Builder builder = OSDisk.builder(); - builder.name("[variables('osDiskName')]"); - builder.caching("ReadWrite"); - builder.createOption("FromImage"); - builder.vhd(VHD.create(vhdUri)); - - if (!imageUri.isEmpty()) { - builder.osType("Linux"); - builder.image(VHD.create(imageUri)); - } - return builder.build(); - } - - private boolean keyVaultInUse(){ - return !Strings.isNullOrEmpty(options.getKeyVaultIdAndSecret()); - } - - /** - * 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. - */ - private 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); - } -} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/GetEnumValue.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/GetEnumValue.java index 4a616137f2..f42bad3f42 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/GetEnumValue.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/GetEnumValue.java @@ -20,7 +20,6 @@ import java.util.EnumSet; public class GetEnumValue { - @SuppressWarnings("unchecked") public static > Enum fromValueOrDefault(String text, Enum defaultValue) { if (text != null) { EnumSet elements = EnumSet.allOf(defaultValue.getDeclaringClass()); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceLiveTest.java index d6fdd3cf09..c3389540c4 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceLiveTest.java @@ -16,21 +16,26 @@ */ package org.jclouds.azurecompute.arm.compute; -import java.util.Map; +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.compute.options.TemplateOptions.Builder.authorizePublicKey; +import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGIONS; + import java.util.Properties; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; -import org.jclouds.compute.RunScriptOnNodesException; -import org.jclouds.compute.domain.ExecResponse; import org.jclouds.compute.domain.NodeMetadata; -import org.jclouds.compute.domain.OperatingSystem; import org.jclouds.compute.domain.Template; +import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.internal.BaseComputeServiceLiveTest; -import org.jclouds.compute.predicates.NodePredicates; -import org.jclouds.domain.LoginCredentials; import org.jclouds.logging.config.LoggingModule; import org.jclouds.logging.slf4j.config.SLF4JLoggingModule; import org.jclouds.providers.ProviderMetadata; @@ -41,29 +46,18 @@ import org.jclouds.scriptbuilder.statements.login.AdminAccess; import org.jclouds.sshj.config.SshjSshClientModule; import org.testng.annotations.Test; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.inject.Module; -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.TEMPLATE; -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; - /** * Live tests for the {@link org.jclouds.compute.ComputeService} integration. */ @Test(groups = "live", singleThreaded = true, testName = "AzureComputeServiceLiveTest") public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest { - protected int nonBlockDurationSeconds = 30; - + public AzureComputeServiceLiveTest() { provider = "azurecompute-arm"; - nonBlockDurationSeconds = 300; - group = "az-u"; } @Override @@ -78,21 +72,20 @@ public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest { @Override protected ProviderMetadata createProviderMetadata() { - AzureComputeProviderMetadata pm = AzureComputeProviderMetadata.builder().build(); - return pm; + return AzureComputeProviderMetadata.builder().build(); } @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, "a4"); - properties.put(TEMPLATE, "locationId=westeurope"); + 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); @@ -102,24 +95,27 @@ public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest { } @Override - protected Template refreshTemplate() { - return this.template = addRunScriptToTemplate(this.buildTemplate(this.client.templateBuilder())); + protected TemplateBuilder templateBuilder() { + return super.templateBuilder().options( + authorizePublicKey(keyPair.get("public")).overrideLoginPrivateKey(keyPair.get("private"))); } @Override protected Template addRunScriptToTemplate(Template template) { - template.getOptions().runScript(Statements.newStatementList(new Statement[]{AdminAccess.standard(), Statements.exec("sleep 50"), InstallJDK.fromOpenJDK()})); + template.getOptions().runScript( + Statements.newStatementList(new Statement[] { AdminAccess.standard(), Statements.exec("sleep 50"), + InstallJDK.fromOpenJDK() })); return template; } - + @Override - @Test( enabled = false) - protected void weCanCancelTasks(NodeMetadata node) throws InterruptedException, ExecutionException { - return; + protected void checkUserMetadataContains(NodeMetadata node, ImmutableMap userMetadata) { + // User metadata not yet supported } @Override - protected Map runScriptWithCreds(String group, OperatingSystem os, LoginCredentials creds) throws RunScriptOnNodesException { - return this.client.runScriptOnNodesMatching(NodePredicates.runningInGroup(group), Statements.newStatementList(Statements.exec("sleep 50"), InstallJDK.fromOpenJDK()), org.jclouds.compute.options.TemplateOptions.Builder.overrideLoginCredentials(creds).nameTask("runScriptWithCreds")); + protected void checkTagsInNodeEquals(NodeMetadata node, ImmutableSet tags) { + // Tags not yet supported } + } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureTemplateBuilderLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureTemplateBuilderLiveTest.java index 875624030e..c20655b091 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureTemplateBuilderLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureTemplateBuilderLiveTest.java @@ -16,33 +16,30 @@ */ package org.jclouds.azurecompute.arm.compute; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.RESOURCE_GROUP_NAME; +import static org.jclouds.compute.util.ComputeServiceUtils.getCores; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.io.IOException; import java.util.Properties; import java.util.Set; -import java.util.concurrent.TimeUnit; import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; +import org.jclouds.azurecompute.arm.domain.Region; import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; +import org.jclouds.compute.domain.OsFamily; +import org.jclouds.compute.domain.Template; import org.jclouds.compute.internal.BaseTemplateBuilderLiveTest; import org.jclouds.providers.ProviderMetadata; import org.jclouds.sshj.config.SshjSshClientModule; import org.testng.annotations.Test; -import com.google.common.collect.ImmutableSet; import com.google.inject.Module; -import static com.google.common.base.Preconditions.checkNotNull; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.RESOURCE_GROUP_NAME; -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING; -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_SCRIPT_COMPLETE; - @Test(groups = "live", testName = "AzureTemplateBuilderLiveTest") public class AzureTemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest { - public String azureGroup; - - @Override - protected Set getIso3166Codes() { - return ImmutableSet.of("US-IA", "US-VA", "US-IL", "US-TX", "US-CA", "IE", "NL", "HK", "SG", "JP-11", "JP-27", "BR", "AU-NSW", "AU-VIC", "IN-GA", "IN-TN", "IN-MH", "CN-SH", "CN-BJ", "CA-ON", "CA-QC"); - } public AzureTemplateBuilderLiveTest() { provider = "azurecompute-arm"; @@ -55,23 +52,33 @@ public class AzureTemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest { @Override protected ProviderMetadata createProviderMetadata() { - AzureComputeProviderMetadata pm = AzureComputeProviderMetadata.builder().build(); - return pm; + return AzureComputeProviderMetadata.builder().build(); } @Override protected Properties setupProperties() { - azureGroup = "jc" + System.getProperty("user.name").substring(0, 3); Properties properties = super.setupProperties(); - long scriptTimeout = TimeUnit.MILLISECONDS.convert(20, TimeUnit.MINUTES); - properties.setProperty(TIMEOUT_SCRIPT_COMPLETE, scriptTimeout + ""); - properties.setProperty(TIMEOUT_NODE_RUNNING, scriptTimeout + ""); - properties.put(RESOURCE_GROUP_NAME, azureGroup); + properties.put(RESOURCE_GROUP_NAME, "jc"); AzureLiveTestUtils.defaultProperties(properties); checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); return properties; - + } + + @Override + @Test + public void testDefaultTemplateBuilder() throws IOException { + Template defaultTemplate = view.getComputeService().templateBuilder().build(); + assertTrue(defaultTemplate.getImage().getOperatingSystem().getVersion().matches("1[45]\\.[01][04]\\.[0-9]-LTS"), + "Version mismatch, expected dd.dd.d-LTS, found: " + defaultTemplate.getImage().getOperatingSystem().getVersion()); + assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true); + assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU); + assertEquals(getCores(defaultTemplate.getHardware()), 1.0d); + } + + @Override + protected Set getIso3166Codes() { + return Region.iso3166Codes(); } } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtensionLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtensionLiveTest.java index 06f9ab7ce1..de44668ed4 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtensionLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtensionLiveTest.java @@ -16,29 +16,35 @@ */ 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.compute.options.TemplateOptions.Builder.authorizePublicKey; +import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGIONS; + +import java.util.Map; +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.ComputeTestUtils; +import org.jclouds.compute.domain.TemplateBuilder; +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. + * Live tests for the {@link org.jclouds.compute.extensions.ImageExtension} + * integration. */ @Test(groups = "live", singleThreaded = true, testName = "AzureComputeImageExtensionLiveTest") public class AzureComputeImageExtensionLiveTest extends BaseImageExtensionLiveTest { @@ -57,34 +63,33 @@ 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(); } + @Override + public TemplateBuilder getNodeTemplate() { + Map keyPair = ComputeTestUtils.setupKeyPair(); + return super.getNodeTemplate().options( + authorizePublicKey(keyPair.get("public")) + .overrideLoginPrivateKey(keyPair.get("private"))); + } } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DeploymentApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DeploymentApiLiveTest.java index 7476828384..42116c2224 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DeploymentApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DeploymentApiLiveTest.java @@ -16,30 +16,19 @@ */ package org.jclouds.azurecompute.arm.features; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + import java.net.URI; import java.util.List; import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; import org.jclouds.azurecompute.arm.domain.Deployment; import org.jclouds.azurecompute.arm.domain.Deployment.ProvisioningState; -import org.jclouds.azurecompute.arm.domain.DeploymentBody; -import org.jclouds.azurecompute.arm.domain.DeploymentProperties; import org.jclouds.azurecompute.arm.domain.Subnet; import org.jclouds.azurecompute.arm.domain.VirtualNetwork; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; -import org.jclouds.azurecompute.arm.util.DeploymentTemplateBuilder; -import org.jclouds.compute.domain.Hardware; -import org.jclouds.compute.domain.HardwareBuilder; -import org.jclouds.compute.domain.Image; -import org.jclouds.compute.domain.ImageBuilder; -import org.jclouds.compute.domain.OperatingSystem; -import org.jclouds.compute.domain.OsFamily; -import org.jclouds.compute.domain.Template; -import org.jclouds.compute.domain.internal.TemplateImpl; -import org.jclouds.compute.options.TemplateOptions; -import org.jclouds.domain.Location; -import org.jclouds.domain.LocationBuilder; -import org.jclouds.domain.LocationScope; import org.jclouds.util.Predicates2; import org.testng.Assert; import org.testng.annotations.AfterClass; @@ -49,10 +38,6 @@ import org.testng.annotations.Test; import com.google.common.base.Predicate; import com.google.common.net.UrlEscapers; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; - @Test(testName = "DeploymentApiLiveTest", singleThreaded = true) public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest { @@ -112,37 +97,6 @@ public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest { return body; } - private Template getTemplate(TemplateOptions options) { - Location provider = (new LocationBuilder()).scope(LocationScope.PROVIDER).id("azurecompute-arm").description("azurecompute-arm").build(); - Location region = (new LocationBuilder()).scope(LocationScope.REGION).id(LOCATION).description("West Europe").parent(provider).build(); - - OperatingSystem os = OperatingSystem.builder() - .family(OsFamily.UBUNTU) - .description("14.04.3-LTS") - .is64Bit(true) - .build(); - - Image image = (new ImageBuilder()) - .id("UbuntuServer14.04.3-LTS") - .providerId("Canonical") - .name("UbuntuServer") - .description("14.04.3-LTS") - .version("14.04.3-LTS") - .operatingSystem(os) - .status(Image.Status.AVAILABLE) - .location(region) - .build(); - - Hardware hardware = (new HardwareBuilder()).id("Standard_A0").build(); - return new TemplateImpl(image, hardware, region, options); - } - - private DeploymentTemplateBuilder getDeploymentTemplateBuilderWithOptions(TemplateOptions options) { - Template template = getTemplate(options); - DeploymentTemplateBuilder templateBuilder = api.deploymentTemplateFactory().create(resourceGroupName, deploymentName, template); - return templateBuilder; - } - @Test public void testValidate(){ Deployment deploymentInvalid = null; @@ -168,12 +122,40 @@ public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest { AzureTemplateOptions options = new AzureTemplateOptions(); options.authorizePublicKey(rsakey); options.subnetId(subnetId); - DeploymentTemplateBuilder templateBuilder = getDeploymentTemplateBuilderWithOptions(options); - DeploymentBody deploymentTemplateBody = templateBuilder.getDeploymentTemplate(); - DeploymentProperties properties = DeploymentProperties.create(deploymentTemplateBody); - - String deploymentTemplate = templateBuilder.getDeploymentTemplateJson(properties); + String deploymentTemplate = "{\n" + + " \"id\": \"/subscriptions/04f7ec88-8e28-41ed-8537-5e17766001f5/resourceGroups/jims216group/providers/Microsoft.Resources/deployments/jcdep1458344383064\",\n" + + " \"name\": \"jcdep1458344383064\",\n" + + " \"properties\": {\n" + + " \"parameters\": {\n" + + " \"newStorageAccountName\": {\n" + + " \"type\": \"String\",\n" + + " \"value\": \"jcres1458344383064\"\n" + + " },\n" + + " \"storageAccountType\": {\n" + + " \"type\": \"String\",\n" + + " \"value\": \"Standard_LRS\"\n" + + " },\n" + + " \"location\": {\n" + + " \"type\": \"String\",\n" + + " \"value\": \"West US\"\n" + + " }\n" + + " },\n" + + " \"mode\": \"Incremental\",\n" + + " \"provisioningState\": \"Accepted\",\n" + + " \"timestamp\": \"2016-03-18T23:39:47.3048037Z\",\n" + + " \"duration\": \"PT2.4433028S\",\n" + + " \"correlationId\": \"8dee9711-8632-4948-9fe6-368bb75e6438\",\n" + + " \"providers\": [{\n" + + " \"namespace\": \"Microsoft.Storage\",\n" + + " \"resourceTypes\": [{\n" + + " \"resourceType\": \"storageAccounts\",\n" + + " \"locations\": [\"westus\"]\n" + + " }]\n" + + " }],\n" + + " \"dependencies\": []\n" + + " }\n" + + "}"; deploymentTemplate = UrlEscapers.urlFormParameterEscaper().escape(deploymentTemplate); Deployment deploymentValid = api().validate(deploymentName, deploymentTemplate); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DeploymentTemplateBuilderTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DeploymentTemplateBuilderTest.java deleted file mode 100644 index 165789998f..0000000000 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DeploymentTemplateBuilderTest.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jclouds.azurecompute.arm.features; - -import java.util.List; -import java.util.Map; - -import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; -import org.jclouds.azurecompute.arm.domain.DeploymentBody; -import org.jclouds.azurecompute.arm.domain.ImageReference; -import org.jclouds.azurecompute.arm.domain.IpConfiguration; -import org.jclouds.azurecompute.arm.domain.IpConfigurationProperties; -import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCardProperties; -import org.jclouds.azurecompute.arm.domain.PublicIPAddressProperties; -import org.jclouds.azurecompute.arm.domain.ResourceDefinition; -import org.jclouds.azurecompute.arm.domain.StorageService; -import org.jclouds.azurecompute.arm.domain.StorageService.StorageServiceProperties; -import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties; -import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; -import org.jclouds.azurecompute.arm.util.DeploymentTemplateBuilder; -import org.jclouds.compute.domain.Hardware; -import org.jclouds.compute.domain.HardwareBuilder; -import org.jclouds.compute.domain.Image; -import org.jclouds.compute.domain.ImageBuilder; -import org.jclouds.compute.domain.OperatingSystem; -import org.jclouds.compute.domain.Template; -import org.jclouds.compute.domain.internal.TemplateImpl; -import org.jclouds.compute.options.TemplateOptions; -import org.jclouds.domain.Location; -import org.jclouds.domain.LocationBuilder; -import org.jclouds.domain.LocationScope; -import org.testng.Assert; -import org.testng.annotations.Test; - -import com.google.common.collect.Iterables; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; - -@Test(groups = "unit", testName = "DeploymentTemplateBuilderTest", singleThreaded = true) -public class DeploymentTemplateBuilderTest extends BaseAzureComputeApiMockTest { - - final String group = "jcgroup"; - final String vnetName = group + "virtualnetwork"; - final String subnetId = ""; - - @Test - public void testResourceGroup() { - DeploymentTemplateBuilder builder = getMockDeploymentTemplateBuilderWithEmptyOptions(); - DeploymentBody deploymentBody = builder.getDeploymentTemplate(); - List resources = deploymentBody.template().resources(); - Map variables = deploymentBody.template().variables(); - - ResourceDefinition resource = getResourceByType(resources, "Microsoft.Storage/storageAccounts"); - - StorageServiceProperties properties = (StorageServiceProperties) resource.properties(); - assertEquals(properties.accountType(), StorageService.AccountType.Standard_LRS); - assertTrue(variables.containsKey(parseVariableName(resource.name()))); - } - - @Test - void testPublicIpAddress() { - DeploymentTemplateBuilder builder = getMockDeploymentTemplateBuilderWithEmptyOptions(); - DeploymentBody deploymentBody = builder.getDeploymentTemplate(); - List resources = deploymentBody.template().resources(); - Map variables = deploymentBody.template().variables(); - - ResourceDefinition resource = getResourceByType(resources, "Microsoft.Network/publicIPAddresses"); - - PublicIPAddressProperties properties = (PublicIPAddressProperties) resource.properties(); - assertEquals(properties.publicIPAllocationMethod(), "Dynamic"); - assertTrue(variables.containsKey(parseVariableName(resource.name()))); - } - - @Test - void testNetworkInterfaceCard() { - DeploymentTemplateBuilder builder = getMockDeploymentTemplateBuilderWithEmptyOptions(); - DeploymentBody deploymentBody = builder.getDeploymentTemplate(); - List resources = deploymentBody.template().resources(); - Map variables = deploymentBody.template().variables(); - - ResourceDefinition resource = getResourceByType(resources, "Microsoft.Network/networkInterfaces"); - - NetworkInterfaceCardProperties properties = (NetworkInterfaceCardProperties) resource.properties(); - List ipConfigs = properties.ipConfigurations(); - assertTrue(ipConfigs.size() > 0); - IpConfigurationProperties ipProperties = ipConfigs.get(0).properties(); - assertEquals(ipProperties.privateIPAllocationMethod(), "Dynamic"); - assertNotNull(ipProperties.publicIPAddress()); - assertNotNull(ipProperties.subnet()); - - assertTrue(variables.containsKey(parseVariableName(resource.name()))); - } - - @Test - void testVirtualMachine() { - DeploymentTemplateBuilder builder = getMockDeploymentTemplateBuilderWithEmptyOptions(); - Template template = builder.getTemplate(); - - DeploymentBody deploymentBody = builder.getDeploymentTemplate(); - List resources = deploymentBody.template().resources(); - Map variables = deploymentBody.template().variables(); - - ResourceDefinition resource = getResourceByType(resources, "Microsoft.Compute/virtualMachines"); - assertNotNull(resource); - - VirtualMachineProperties properties = (VirtualMachineProperties) resource.properties(); - assertEquals(properties.hardwareProfile().vmSize(), template.getHardware().getId()); - - ImageReference image = properties.storageProfile().imageReference(); - assertEquals(image.publisher(), template.getImage().getProviderId()); - assertEquals(image.offer(), template.getImage().getName()); - assertEquals(image.sku(), template.getImage().getVersion()); - assertEquals(image.version(), "latest"); - - assertTrue(variables.containsKey(parseVariableName(resource.name()))); - } - - @Test - void testAddStorageResourceWhenNameIsLongerThan24Chars() { - String name = "thishasmorethan24characters"; - DeploymentTemplateBuilder builder = getMockDeploymentTemplateBuilderWithEmptyOptions(name); - - DeploymentBody deploymentBody = builder.getDeploymentTemplate(); - assertTrue(Iterables.contains(deploymentBody.template().variables().keySet(), "storageAccountName")); - String storageAccountName = deploymentBody.template().variables().get("storageAccountName"); - assertEquals(storageAccountName.length(), 24); - assertEquals(storageAccountName.substring(0, 10), "thishasmor"); - assertEquals(storageAccountName.substring(storageAccountName.length() - 10, storageAccountName.length()), "characters"); - } - - @Test - void testAddStorageResourceWhenNameIsExactly24Chars() { - String name = "ithasexactly24characters"; - DeploymentTemplateBuilder builder = getMockDeploymentTemplateBuilderWithEmptyOptions(name); - - DeploymentBody deploymentBody = builder.getDeploymentTemplate(); - assertTrue(Iterables.contains(deploymentBody.template().variables().keySet(), "storageAccountName")); - assertEquals(deploymentBody.template().variables().get("storageAccountName").length(), 24); - assertEquals(deploymentBody.template().variables().get("storageAccountName"), name); - } - - @Test - void testAddStorageResourceWhenNameIsLessThan3Chars() { - String name = "3c"; - DeploymentTemplateBuilder builder = getMockDeploymentTemplateBuilderWithEmptyOptions(name); - - DeploymentBody deploymentBody = builder.getDeploymentTemplate(); - assertTrue(Iterables.contains(deploymentBody.template().variables().keySet(), "storageAccountName")); - assertEquals(deploymentBody.template().variables().get("storageAccountName").length(), 6); - assertEquals(deploymentBody.template().variables().get("storageAccountName").substring(0, 2), name); - } - - @Test - void testCustomOptions(){ - final String dnsLabelPrefix = "mydnslabel"; - final String customData = "echo customData"; - final String customData64 = "ZWNobyBjdXN0b21EYXRh"; - final String keyvaultString = "/url/to/vault/:publickeysecret"; - - AzureTemplateOptions options = new AzureTemplateOptions() - .customData(customData) - .DNSLabelPrefix(dnsLabelPrefix) - .keyVaultIdAndSecret(keyvaultString); - - options.virtualNetworkName(vnetName); - options.subnetId(subnetId); - - assertEquals(options.as(AzureTemplateOptions.class).getCustomData(), customData); - assertEquals(options.getDNSLabelPrefix(), dnsLabelPrefix); - assertEquals(options.as(AzureTemplateOptions.class).getKeyVaultIdAndSecret(), keyvaultString); - - DeploymentTemplateBuilder builder = getMockDeploymentTemplateBuilderWithOptions(options); - - DeploymentBody deploymentBody = builder.getDeploymentTemplate(); - - List resources = deploymentBody.template().resources(); - ResourceDefinition publicIpResource = getResourceByType(resources, "Microsoft.Network/publicIPAddresses"); - assertNotNull(publicIpResource); - - PublicIPAddressProperties ipProperties = (PublicIPAddressProperties) publicIpResource.properties(); - assertEquals(ipProperties.dnsSettings().domainNameLabel(), dnsLabelPrefix); - - ResourceDefinition vmResource = getResourceByType(resources, "Microsoft.Compute/virtualMachines"); - assertNotNull(vmResource); - - VirtualMachineProperties virtualMachineProperties = (VirtualMachineProperties) vmResource.properties(); - assertEquals(virtualMachineProperties.osProfile().customData(), customData64); - - //populated when keyvault is used to get public key. - assertNotNull(virtualMachineProperties.osProfile().linuxConfiguration().ssh().publicKeys()); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - void testSimplifyPortsWithPortsNull() { - int[] ports = null; - DeploymentTemplateBuilder.simplifyPorts(ports); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - void testSimplifyPortsWithPortsEmpty() { - int[] ports = new int[0]; - DeploymentTemplateBuilder.simplifyPorts(ports); - } - - @Test - void testSimplifyPorts() { - int[] ports = {8084, 22, 8081, 8080, 8082}; - List ranges = DeploymentTemplateBuilder.simplifyPorts(ports); - assertEquals(ranges.size(), 3); - assertEquals(ranges.get(0), "22"); - assertEquals(ranges.get(1), "8080-8082"); - assertEquals(ranges.get(2), "8084"); - } - - private Template getMockTemplate(TemplateOptions options) { - ((AzureTemplateOptions)options).virtualNetworkName(vnetName); - ((AzureTemplateOptions)options).subnetId(subnetId); - - Location provider = (new LocationBuilder()).scope(LocationScope.PROVIDER).id("azurecompute-arm").description("azurecompute-arm").build(); - Location region = (new LocationBuilder()).scope(LocationScope.REGION).id("northeurope").description("North Europe").parent(provider).build(); - OperatingSystem os = OperatingSystem.builder().name("osName").version("osVersion").description("osDescription").arch("X86_32").build(); - //Note that version is set to "latest" - Image image = (new ImageBuilder()).id("imageId").providerId("imageId").name("imageName").description("imageDescription").version("sku").operatingSystem(os).status(Image.Status.AVAILABLE).location(region).build(); - Hardware hardware = (new HardwareBuilder()).id("Standard_A0").build(); - return new TemplateImpl(image, hardware, region, options); - } - - private DeploymentTemplateBuilder getMockDeploymentTemplateBuilderWithEmptyOptions() { - return getMockDeploymentTemplateBuilderWithEmptyOptions("mydeployment"); - } - - private DeploymentTemplateBuilder getMockDeploymentTemplateBuilderWithEmptyOptions(String name) { - AzureTemplateOptions options = new AzureTemplateOptions(); - options.virtualNetworkName(vnetName); - options.subnetId(subnetId); - - Template template = getMockTemplate(options); - DeploymentTemplateBuilder templateBuilder = api.deploymentTemplateFactory().create(group, name, template); - return templateBuilder; - } - - private DeploymentTemplateBuilder getMockDeploymentTemplateBuilderWithOptions(TemplateOptions options) { - return getMockDeploymentTemplateBuilderWithOptions("mydeployment", options); - } - - private DeploymentTemplateBuilder getMockDeploymentTemplateBuilderWithOptions(String name, TemplateOptions options) { - ((AzureTemplateOptions)options).virtualNetworkName(vnetName); - ((AzureTemplateOptions)options).subnetId(subnetId); - - Template template = getMockTemplate(options); - DeploymentTemplateBuilder templateBuilder = api.deploymentTemplateFactory().create(group, name, template); - return templateBuilder; - } - - private ResourceDefinition getResourceByType(List resources, String type) { - for (ResourceDefinition r : resources) { - if (r.type().equals(type)) { - return r; - } - } - Assert.fail("Resource with type: " + type + " not found"); - return null; - } - - private String parseVariableName(String variable) { - String[] parts = variable.split("\'"); - assertTrue(parts.length == 3); - return parts[1]; - } -} - diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApiMockTest.java index adefd95d41..2d43694684 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApiMockTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApiMockTest.java @@ -83,8 +83,6 @@ public class NetworkSecurityGroupApiMockTest extends BaseAzureComputeApiMockTest } public void getNetworkSecurityGroup() throws InterruptedException { - NetworkSecurityGroup nsg = createGroup(); - server.enqueue(jsonResponse("/networksecuritygroupget.json").setResponseCode(200)); final NetworkSecurityGroupApi nsgApi = api.getNetworkSecurityGroupApi(resourcegroup); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApiMockTest.java index 436cb91f81..b510580655 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApiMockTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApiMockTest.java @@ -147,8 +147,7 @@ public class PublicIPAddressApiMockTest extends BaseAzureComputeApiMockTest { PublicIPAddressProperties properties = PublicIPAddressProperties.create(null, null, "Static", 4, null, DnsSettings.create("foobar", "foobar.northeurope.cloudapp.azure.com", null)); - PublicIPAddress ip = ipApi.createOrUpdate(publicIpName, location, tags, properties); - + ipApi.createOrUpdate(publicIpName, location, tags, properties); } public void deletePublicIPAddress() throws InterruptedException { diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceProviderAPIMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceProviderAPIMockTest.java index 70f2ad606f..3c90d42f92 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceProviderAPIMockTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceProviderAPIMockTest.java @@ -31,7 +31,6 @@ public class ResourceProviderAPIMockTest extends BaseAzureComputeApiMockTest { final String apiVersion = "2015-01-01"; final String resource = "Microsoft.Compute"; - private final String vm_resource = "virtualMachines"; public void getPublicIPAddressInfo() throws InterruptedException { server.enqueue(jsonResponse("/getresourceprovidermetadata.json")); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiMockTest.java index 39ecd2babc..e3fdf6d56b 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiMockTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiMockTest.java @@ -235,41 +235,6 @@ public class StorageAccountApiMockTest extends BaseAzureComputeApiMockTest { "/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE?api-version=2015-06-15"); } - private StorageService getStrorageAccount() { - DateService DATE_SERVICE = new SimpleDateFormatDateService(); - Map endpoints = new HashMap(); - endpoints.put("blob", "https://TESTSTORAGE.blob.core.windows.net/"); - endpoints.put("file", "https://TESTSTORAGE.file.core.windows.net/"); - endpoints.put("queue", "https://TESTSTORAGE.queue.core.windows.net/"); - endpoints.put("table", "https://TESTSTORAGE.table.core.windows.net/"); - Map secondaryEndpoints = new HashMap(); - secondaryEndpoints.put("blob", "https://TESTSTORAGE-secondary.blob.core.windows.net/"); - secondaryEndpoints.put("queue", "https://TESTSTORAGE-secondary.queue.core.windows.net/"); - secondaryEndpoints.put("table", "https://TESTSTORAGE-secondary.table.core.windows.net/"); - - - String location = "westus"; - String secondaryLocation = "eastus"; - final StorageService.StorageServiceProperties props = StorageService.StorageServiceProperties.create( - StorageService.AccountType.Standard_RAGRS, - DATE_SERVICE.iso8601DateOrSecondsDateParse("2016-02-24T13:04:45.0890883Z"), - endpoints, - location, - StorageService.Status.Succeeded, - secondaryEndpoints, secondaryLocation, - StorageService.RegionStatus.Available, - StorageService.RegionStatus.Available); - - final Map tags = ImmutableMap.of( - "key1", "value1", - "key2", "value2"); - - return StorageService.create( - "/subscriptions/SUBSCRIPTIONID/resourceGroups/resourceGroup" + - "/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE", - "TESTSTORAGE", location, tags, null, props); - } - private List expected() throws MalformedURLException { DateService DATE_SERVICE = new SimpleDateFormatDateService(); Map endpoints = new HashMap(); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/SubnetApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/SubnetApiMockTest.java index bfcf188dc5..0113201f55 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/SubnetApiMockTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/SubnetApiMockTest.java @@ -16,18 +16,17 @@ */ package org.jclouds.azurecompute.arm.features; -import com.squareup.okhttp.mockwebserver.RecordedRequest; -import org.jclouds.azurecompute.arm.domain.Subnet; -import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; -import org.testng.annotations.Test; - -import java.util.List; - import static com.google.common.collect.Iterables.isEmpty; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +import java.util.List; + +import org.jclouds.azurecompute.arm.domain.Subnet; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; +import org.testng.annotations.Test; @Test(groups = "unit", testName = "SubnetApiMockTest", singleThreaded = true) @@ -135,6 +134,6 @@ public class SubnetApiMockTest extends BaseAzureComputeApiMockTest { assertFalse(status); String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/virtualNetworks/%s/subnets/%s?%s", subscriptionid, resourcegroup, virtualNetwork, subnetName, apiVersion); - RecordedRequest rr = assertSent(server, "DELETE", path); + assertSent(server, "DELETE", path); } } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/TemplateToDeploymentTemplateLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/TemplateToDeploymentTemplateLiveTest.java deleted file mode 100644 index 3b876636e1..0000000000 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/TemplateToDeploymentTemplateLiveTest.java +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jclouds.azurecompute.arm.features; - -import java.net.URI; - -import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; -import org.jclouds.azurecompute.arm.domain.Deployment; -import org.jclouds.azurecompute.arm.domain.DeploymentBody; -import org.jclouds.azurecompute.arm.domain.DeploymentProperties; -import org.jclouds.azurecompute.arm.domain.Subnet; -import org.jclouds.azurecompute.arm.domain.VirtualNetwork; -import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; -import org.jclouds.azurecompute.arm.util.DeploymentTemplateBuilder; -import org.jclouds.compute.domain.Hardware; -import org.jclouds.compute.domain.HardwareBuilder; -import org.jclouds.compute.domain.Image; -import org.jclouds.compute.domain.ImageBuilder; -import org.jclouds.compute.domain.OperatingSystem; -import org.jclouds.compute.domain.OsFamily; -import org.jclouds.compute.domain.Template; -import org.jclouds.compute.domain.internal.TemplateImpl; -import org.jclouds.compute.options.TemplateOptions; -import org.jclouds.domain.Location; -import org.jclouds.domain.LocationBuilder; -import org.jclouds.domain.LocationScope; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - -import com.google.common.net.UrlEscapers; - -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; - -@Test(groups = "live", testName = "TemplateToDeploymentTemplateLiveTest", singleThreaded = true) -public class TemplateToDeploymentTemplateLiveTest extends BaseAzureComputeApiLiveTest { - - private int maxTestDuration = 400; - private int pollingInterval = 3; // how frequently to poll for create status - private String resourceGroupName; - private String deploymentName; - private String vnetName; - private String subnetId; - private String virtualNetworkName; - - @BeforeClass - @Override - public void setup() { - super.setup(); - resourceGroupName = String.format("rg-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); - assertNotNull(createResourceGroup(resourceGroupName)); - virtualNetworkName = String.format("vn-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); - - //Subnets belong to a virtual network so that needs to be created first - VirtualNetwork vn = createDefaultVirtualNetwork(resourceGroupName, virtualNetworkName, "10.2.0.0/16", LOCATION); - assertNotNull(vn); - vnetName = vn.name(); - - //Subnet needs to be up & running before NIC can be created - String subnetName = String.format("s-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); - Subnet subnet = createDefaultSubnet(resourceGroupName, subnetName, virtualNetworkName, "10.2.0.0/23"); - assertNotNull(subnet); - assertNotNull(subnet.id()); - subnetId = subnet.id(); - } - - @AfterClass - @Override - protected void tearDown() { - super.tearDown(); - URI uri = deleteResourceGroup(resourceGroupName); - assertResourceDeleted(uri); - } - - @Test - public void testValidateDeploymentTemplateLinuxNodeWithOptions() { - Long now = System.currentTimeMillis(); - deploymentName = "jc" + now; - - AzureTemplateOptions options = new AzureTemplateOptions(); - options.virtualNetworkName(vnetName); - options.subnetId(subnetId); - - options.inboundPorts(22, 8080); - - DeploymentTemplateBuilder templateBuilder = getDeploymentTemplateBuilderWithOptions(options); - - DeploymentBody deploymentTemplateBody = templateBuilder.getDeploymentTemplate(); - - DeploymentProperties properties = DeploymentProperties.create(deploymentTemplateBody); - - String deploymentTemplate = templateBuilder.getDeploymentTemplateJson(properties); - deploymentTemplate = UrlEscapers.urlFormParameterEscaper().escape(deploymentTemplate); - - //Validates that template is syntactically correct - Deployment deployment = api().validate(deploymentName, deploymentTemplate); - assertNotNull(deployment); - } - - @Test - public void testValidateDeploymentTemplateLinuxNode() { - Long now = System.currentTimeMillis(); - deploymentName = "jc" + now; - - DeploymentTemplateBuilder templateBuilder = getDeploymentTemplateBuilderWithEmptyOptions(); - - DeploymentBody deploymentTemplateBody = templateBuilder.getDeploymentTemplate(); - - DeploymentProperties properties = DeploymentProperties.create(deploymentTemplateBody); - - String deploymentTemplate = templateBuilder.getDeploymentTemplateJson(properties); - deploymentTemplate = UrlEscapers.urlFormParameterEscaper().escape(deploymentTemplate); - - //Validates that template is syntactically correct - Deployment deployment = api().validate(deploymentName, deploymentTemplate); - assertNotNull(deployment); - } - - @Test - public void testValidateDeploymentTemplateWithCustomOptions() { - Long now = System.currentTimeMillis(); - deploymentName = "jc" + now; - - String rsakey = new String("ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAmfk/QSF0pvnrpdz+Ah2KulGruKU+8FFBdlw938MpOysRdmp7uwpH6Z7+5VNGNdxFIAyc/W3UaZXF9hTsU8+78TlwkZpsr2mzU+ycu37XLAQ8Uv7hjsAN0DkKKPrZ9lgUUfZVKV/8E/JIAs03gIbL6zO3y7eYJQ5fNeZb+nji7tQT+YLpGq/FDegvraPKVMQbCSCZhsHyWhdPLyFlu9/30npZ0ahYOPI/KyZxFDtM/pHp88+ZAk9Icq5owaLRWcJQqrBGWqjbZnHtjdDqvHZ+C0wPhdJZPyfkHOrSYTwSQBXfX4JLRRCz3J1jf62MbQWT1o6Y4JEs1ZP1Skxu6zR96Q== mocktest"); - TemplateOptions options = new AzureTemplateOptions() - .DNSLabelPrefix("mydnslabel") - .virtualNetworkAddressPrefix("10.0.0.0/20") - .subnetAddressPrefix("10.0.0.0/25") - .authorizePublicKey(rsakey); - - ((AzureTemplateOptions)options).virtualNetworkName(vnetName); - ((AzureTemplateOptions)options).subnetId(subnetId); - - DeploymentTemplateBuilder templateBuilder = getDeploymentTemplateBuilderWithOptions(options); - - DeploymentBody deploymentTemplateBody = templateBuilder.getDeploymentTemplate(); - - DeploymentProperties properties = DeploymentProperties.create(deploymentTemplateBody); - - String deploymentTemplate = templateBuilder.getDeploymentTemplateJson(properties); - deploymentTemplate = UrlEscapers.urlFormParameterEscaper().escape(deploymentTemplate); - - Deployment deployment = api().validate(deploymentName, deploymentTemplate); - assertNotNull(deployment); - } - - @Test - public void testValidateDeploymentTemplateLinuxNodeWithSSH() { - Long now = System.currentTimeMillis(); - deploymentName = "jc" + now; - - String rsakey = new String("ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAmfk/QSF0pvnrpdz+Ah2KulGruKU+8FFBdlw938MpOysRdmp7uwpH6Z7+5VNGNdxFIAyc/W3UaZXF9hTsU8+78TlwkZpsr2mzU+ycu37XLAQ8Uv7hjsAN0DkKKPrZ9lgUUfZVKV/8E/JIAs03gIbL6zO3y7eYJQ5fNeZb+nji7tQT+YLpGq/FDegvraPKVMQbCSCZhsHyWhdPLyFlu9/30npZ0ahYOPI/KyZxFDtM/pHp88+ZAk9Icq5owaLRWcJQqrBGWqjbZnHtjdDqvHZ+C0wPhdJZPyfkHOrSYTwSQBXfX4JLRRCz3J1jf62MbQWT1o6Y4JEs1ZP1Skxu6zR96Q== mocktest"); - - AzureTemplateOptions options = new AzureTemplateOptions(); - options.virtualNetworkName(vnetName); - options.subnetId(subnetId); - - options.authorizePublicKey(rsakey); - DeploymentTemplateBuilder templateBuilder = getDeploymentTemplateBuilderWithOptions(options); - - DeploymentBody deploymentTemplateBody = templateBuilder.getDeploymentTemplate(); - - DeploymentProperties properties = DeploymentProperties.create(deploymentTemplateBody); - - String deploymentTemplate = templateBuilder.getDeploymentTemplateJson(properties); - deploymentTemplate = UrlEscapers.urlFormParameterEscaper().escape(deploymentTemplate); - - Deployment deployment = api().validate(deploymentName, deploymentTemplate); - assertNotNull(deployment); - } - - @Test - public void testCreateDeploymentTemplateLinuxNode() { - Long now = System.currentTimeMillis(); - deploymentName = "jc" + now; - - String rsakey = new String("ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAmfk/QSF0pvnrpdz+Ah2KulGruKU+8FFBdlw938MpOysRdmp7uwpH6Z7+5VNGNdxFIAyc/W3UaZXF9hTsU8+78TlwkZpsr2mzU+ycu37XLAQ8Uv7hjsAN0DkKKPrZ9lgUUfZVKV/8E/JIAs03gIbL6zO3y7eYJQ5fNeZb+nji7tQT+YLpGq/FDegvraPKVMQbCSCZhsHyWhdPLyFlu9/30npZ0ahYOPI/KyZxFDtM/pHp88+ZAk9Icq5owaLRWcJQqrBGWqjbZnHtjdDqvHZ+C0wPhdJZPyfkHOrSYTwSQBXfX4JLRRCz3J1jf62MbQWT1o6Y4JEs1ZP1Skxu6zR96Q== mocktest"); - - AzureTemplateOptions options = new AzureTemplateOptions(); - options.virtualNetworkName(vnetName); - options.subnetId(subnetId); - - options.authorizePublicKey(rsakey); - options.inboundPorts(22, 8080); - DeploymentTemplateBuilder templateBuilder = getDeploymentTemplateBuilderWithOptions(options); - - DeploymentBody deploymentTemplateBody = templateBuilder.getDeploymentTemplate(); - DeploymentProperties properties = DeploymentProperties.create(deploymentTemplateBody); - - String deploymentTemplate = templateBuilder.getDeploymentTemplateJson(properties); - deploymentTemplate = UrlEscapers.urlFormParameterEscaper().escape(deploymentTemplate); - - //creates an actual VM using deployment template - Deployment deployment = api().create(deploymentName, deploymentTemplate); - - Deployment.ProvisioningState state = Deployment.ProvisioningState.fromValue(deployment.properties().provisioningState()); - int testTime = 0; - while (testTime < maxTestDuration) { - if ((state == Deployment.ProvisioningState.SUCCEEDED) || - (state == Deployment.ProvisioningState.CANCELED) || - (state == Deployment.ProvisioningState.DELETED) || - (state == Deployment.ProvisioningState.FAILED)) { - break; - } - - // sleep a little bit before polling, timeout after a fixed time - try { - Thread.sleep(pollingInterval * 1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - testTime += pollingInterval; - - deployment = api().get(deploymentName); - assertNotNull(deployment); - state = Deployment.ProvisioningState.fromValue(deployment.properties().provisioningState()); - } - assertTrue(state == Deployment.ProvisioningState.SUCCEEDED); - assertNotNull(deployment); - } - - private Template getTemplate(TemplateOptions options) { - Location provider = (new LocationBuilder()).scope(LocationScope.PROVIDER).id("azurecompute-arm").description("azurecompute-arm").build(); - Location region = (new LocationBuilder()).scope(LocationScope.REGION).id(LOCATION).description(LOCATIONDESCRIPTION).parent(provider).build(); - - OperatingSystem os = OperatingSystem.builder() - .family(OsFamily.UBUNTU) - .description("14.04.3-LTS") - .is64Bit(true) - .build(); - - Image image = (new ImageBuilder()) - .id("UbuntuServer14.04.3-LTS") - .providerId("Canonical") - .name("UbuntuServer") - .description("14.04.3-LTS") - .version("14.04.3-LTS") - .operatingSystem(os) - .status(Image.Status.AVAILABLE) - .location(region) - .build(); - - Hardware hardware = (new HardwareBuilder()).id("Standard_A0").build(); - return new TemplateImpl(image, hardware, region, options); - } - - private DeploymentTemplateBuilder getDeploymentTemplateBuilderWithEmptyOptions() { - AzureTemplateOptions options = new AzureTemplateOptions(); - options.virtualNetworkName(vnetName); - options.subnetId(subnetId); - - Template template = getTemplate(options); - DeploymentTemplateBuilder templateBuilder = api.deploymentTemplateFactory().create(resourceGroupName, deploymentName, template); - return templateBuilder; - } - - private DeploymentTemplateBuilder getDeploymentTemplateBuilderWithOptions(TemplateOptions options) { - Template template = getTemplate(options); - DeploymentTemplateBuilder templateBuilder = api.deploymentTemplateFactory().create(resourceGroupName, deploymentName, template); - return templateBuilder; - } - - private DeploymentApi api() { - return api.getDeploymentApi(resourceGroupName); - } -} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineApiLiveTest.java index 27023701b0..0973693ee2 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineApiLiveTest.java @@ -16,6 +16,10 @@ */ package org.jclouds.azurecompute.arm.features; +import static org.jclouds.util.Predicates2.retry; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + import java.net.URI; import java.util.ArrayList; import java.util.Arrays; @@ -41,6 +45,7 @@ import org.jclouds.azurecompute.arm.domain.Subnet; import org.jclouds.azurecompute.arm.domain.VHD; import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance; +import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance.VirtualMachineStatus.PowerState; import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; import org.testng.Assert; @@ -48,16 +53,9 @@ import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; -import com.google.common.base.Function; import com.google.common.base.Predicate; -import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; -import com.google.gson.internal.LinkedTreeMap; - -import static org.jclouds.util.Predicates2.retry; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; @Test(groups = "live", testName = "VirtualMachineApiLiveTest") public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { @@ -125,7 +123,7 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { }, 60 * 20 * 1000).apply(vmName); assertTrue(jobDone, "create operation did not complete in the configured timeout"); - String status = api().get(vmName).properties().provisioningState(); + VirtualMachineProperties.ProvisioningState status = api().get(vmName).properties().provisioningState(); // Cannot be creating anymore. Should be succeeded or running but not failed. assertTrue(!status.equals("Creating")); assertTrue(!status.equals("Failed")); @@ -146,21 +144,21 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { @Test(dependsOnMethods = "testStart") public void testStop() { api().stop(vmName); - assertTrue(stateReached("PowerState", "VM stopped"), "stop operation did not complete in the configured timeout"); + assertTrue(stateReached(PowerState.STOPPED), "stop operation did not complete in the configured timeout"); } @Test(dependsOnMethods = "testGet") public void testStart() { api().start(vmName); - assertTrue(stateReached("PowerState", "VM running"), "start operation did not complete in the configured timeout"); + assertTrue(stateReached(PowerState.RUNNING), "start operation did not complete in the configured timeout"); } @Test(dependsOnMethods = "testStop") public void testRestart() { api().start(vmName); - assertTrue(stateReached("PowerState", "VM running"), "start operation did not complete in the configured timeout"); + assertTrue(stateReached(PowerState.RUNNING), "start operation did not complete in the configured timeout"); api().restart(vmName); - assertTrue(stateReached("PowerState", "VM running"), "restart operation did not complete in the configured timeout"); + assertTrue(stateReached(PowerState.RUNNING), "restart operation did not complete in the configured timeout"); } @Test(dependsOnMethods = "testCreate") @@ -180,10 +178,11 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { @Test(dependsOnMethods = "testRestart") public void testGeneralize() throws IllegalStateException { api().stop(vmName); - assertTrue(stateReached("PowerState", "VM stopped"), "restart operation did not complete in the configured timeout"); + assertTrue(stateReached(PowerState.STOPPED), "restart operation did not complete in the configured timeout"); api().generalize(vmName); } + @SuppressWarnings("unchecked") @Test(dependsOnMethods = "testGeneralize") public void testCapture() throws IllegalStateException { URI uri = api().capture(vmName, vmName, vmName); @@ -192,17 +191,17 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { List definitions = api.getJobApi().captureStatus(uri); if (definitions != null) { for (ResourceDefinition definition : definitions) { - LinkedTreeMap properties = (LinkedTreeMap) definition.properties(); + Map properties = (Map) definition.properties(); Object storageObject = properties.get("storageProfile"); - LinkedTreeMap properties2 = (LinkedTreeMap) storageObject; + Map properties2 = (Map) storageObject; Object osDiskObject = properties2.get("osDisk"); - LinkedTreeMap osProperties = (LinkedTreeMap) osDiskObject; + Map osProperties = (Map) osDiskObject; Object dataDisksObject = properties2.get("dataDisks"); - ArrayList dataProperties = (ArrayList) dataDisksObject; - LinkedTreeMap datadiskObject = (LinkedTreeMap) dataProperties.get(0); + List dataProperties = (List) dataDisksObject; + Map datadiskObject = (Map) dataProperties.get(0); - Assert.assertNotNull(osProperties.get("name")); - Assert.assertNotNull(datadiskObject.get("name")); + assertNotNull(osProperties.get("name")); + assertNotNull(datadiskObject.get("name")); } } } @@ -245,7 +244,7 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { DiagnosticsProfile.BootDiagnostics.create(true, blob); DiagnosticsProfile diagnosticsProfile = DiagnosticsProfile.create(bootDiagnostics); VirtualMachineProperties properties = VirtualMachineProperties.create(null, - null, null, hwProf, storageProfile, osProfile, networkProfile, diagnosticsProfile, "Creating"); + null, null, hwProf, storageProfile, osProfile, networkProfile, diagnosticsProfile, VirtualMachineProperties.ProvisioningState.CREATING); return properties; } @@ -261,37 +260,15 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { return api.getNetworkInterfaceCardApi(resourceGroupName).createOrUpdate(networkInterfaceCardName, locationName, networkInterfaceCardProperties, tags); } - private boolean deleteStorageService(String resourceGroupName, String storageServiceName) { - return api.getStorageAccountApi(resourceGroupName).delete(storageServiceName); + private boolean waitForState(String name, final PowerState state) { + return api().getInstanceDetails(name).powerState().equals(state); } - private boolean waitForState(String name, final String state, final String displayStatus) { - return FluentIterable.from(api().getInstanceDetails(name).statuses()) - .filter(new Predicate() { - @Override - public boolean apply(VirtualMachineInstance.VirtualMachineStatus input) { - return input.code().substring(0, 10).equals(state); - } - }) - .transform(new Function() { - @Override - public String apply(VirtualMachineInstance.VirtualMachineStatus input) { - return input.displayStatus(); - } - }) - .anyMatch(new Predicate() { - @Override - public boolean apply(String input) { - return input.equals(displayStatus); - } - }); - } - - private boolean stateReached(final String state, final String displayStatus) { + private boolean stateReached(final PowerState state) { return retry(new Predicate() { @Override public boolean apply(String name) { - return waitForState(name, state, displayStatus); + return waitForState(name, state); } }, 60 * 4 * 1000).apply(vmName); } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineApiMockTest.java index f6583c8139..bb36dc5165 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineApiMockTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineApiMockTest.java @@ -16,35 +16,36 @@ */ package org.jclouds.azurecompute.arm.features; -import com.google.common.collect.ImmutableList; -import com.squareup.okhttp.mockwebserver.MockResponse; +import java.net.URI; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.jclouds.azurecompute.arm.domain.DataDisk; +import org.jclouds.azurecompute.arm.domain.DiagnosticsProfile; import org.jclouds.azurecompute.arm.domain.HardwareProfile; import org.jclouds.azurecompute.arm.domain.IdReference; import org.jclouds.azurecompute.arm.domain.ImageReference; -import org.jclouds.azurecompute.arm.domain.VirtualMachine; -import org.jclouds.azurecompute.arm.domain.VHD; +import org.jclouds.azurecompute.arm.domain.NetworkProfile; import org.jclouds.azurecompute.arm.domain.OSDisk; import org.jclouds.azurecompute.arm.domain.OSProfile; -import org.jclouds.azurecompute.arm.domain.DiagnosticsProfile; -import org.jclouds.azurecompute.arm.domain.NetworkProfile; import org.jclouds.azurecompute.arm.domain.StorageProfile; -import org.jclouds.azurecompute.arm.domain.DataDisk; +import org.jclouds.azurecompute.arm.domain.VHD; +import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance; import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; import org.testng.annotations.Test; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; -import java.util.Date; -import java.text.SimpleDateFormat; -import java.text.DateFormat; +import com.google.common.collect.ImmutableList; +import com.squareup.okhttp.mockwebserver.MockResponse; import static com.google.common.collect.Iterables.isEmpty; import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNull; import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; @Test(groups = "unit", testName = "VirtualMachineApiMockTest", singleThreaded = true) @@ -55,14 +56,14 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); assertEquals(vmAPI.get("windowsmachine"), getVM()); assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + - "/virtualMachines/windowsmachine?api-version=2015-06-15"); + "/virtualMachines/windowsmachine?api-version=2016-03-30"); } public void testGetEmpty() throws Exception { server.enqueue(new MockResponse().setResponseCode(404)); final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); assertNull(vmAPI.get("windowsmachine")); assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + - "/virtualMachines/windowsmachine?api-version=2015-06-15"); + "/virtualMachines/windowsmachine?api-version=2016-03-30"); } public void testGetInstanceDetails() throws Exception { @@ -76,7 +77,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { assertEquals(actual.statuses().get(0).level(), expected.statuses().get(0).level()); //assertEquals(actual.statuses().get(0).time().toString(), expected.statuses().get(0).time().toString()); assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + - "/virtualMachines/windowsmachine/instanceView?api-version=2015-06-15"); + "/virtualMachines/windowsmachine/instanceView?api-version=2016-03-30"); } public void testGetInstanceDetailsEmpty() throws Exception { @@ -84,7 +85,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); assertNull(vmAPI.getInstanceDetails("windowsmachine")); assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + - "/virtualMachines/windowsmachine/instanceView?api-version=2015-06-15"); + "/virtualMachines/windowsmachine/instanceView?api-version=2016-03-30"); } public void testList() throws Exception { @@ -109,7 +110,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { VirtualMachine vm = vmAPI.create("windowsmachine", "westus", getProperties()); assertEquals(vm, getVM()); assertSent(server, "PUT", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + - "/virtualMachines/windowsmachine?api-version=2015-06-15&validating=false", + "/virtualMachines/windowsmachine?validating=false&api-version=2016-03-30", "{\"location\":\"westus\",\"properties\":" + "{\"vmId\":\"27ee085b-d707-xxxx-yyyy-2370e2eb1cc1\"," + "\"hardwareProfile\":{\"vmSize\":\"Standard_D1\"}," + @@ -118,7 +119,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { "\"vhd\":{\"uri\":\"https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd\"},\"caching\":\"ReadWrite\",\"createOption\":\"FromImage\"},\"dataDisks\":[]}," + "\"osProfile\":{\"computerName\":\"windowsmachine\",\"adminUsername\":\"azureuser\",\"windowsConfiguration\":{\"provisionVMAgent\":false,\"enableAutomaticUpdates\":true}}," + "\"networkProfile\":{\"networkInterfaces\":[{\"id\":\"/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Network/networkInterfaces/windowsmachine167\"}]}," + - "\"diagnosticsProfile\":{\"bootDiagnostics\":{\"enabled\":true,\"storageUri\":\"https://groupname2760.blob.core.windows.net/\"}},\"provisioningState\":\"Creating\"}}"); + "\"diagnosticsProfile\":{\"bootDiagnostics\":{\"enabled\":true,\"storageUri\":\"https://groupname2760.blob.core.windows.net/\"}},\"provisioningState\":\"CREATING\"}}"); } @@ -133,7 +134,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { assertNull(uri); assertSent(server, "DELETE", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + - "/virtualMachines/windowsmachine?api-version=2015-06-15"); + "/virtualMachines/windowsmachine?api-version=2016-03-30"); } public void testDelete() throws Exception { server.enqueue(response202WithHeader()); @@ -146,7 +147,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { assertNotNull(uri); assertSent(server, "DELETE", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + - "/virtualMachines/windowsmachine?api-version=2015-06-15"); + "/virtualMachines/windowsmachine?api-version=2016-03-30"); } public void testStart() throws Exception { @@ -231,7 +232,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { "https://groupname2760.blob.core.windows.net/"); DiagnosticsProfile diagnosticsProfile = DiagnosticsProfile.create(bootDiagnostics); VirtualMachineProperties properties = VirtualMachineProperties.create("27ee085b-d707-xxxx-yyyy-2370e2eb1cc1", - null, null, hwProf, storageProfile, osProfile, networkProfile, diagnosticsProfile, "Creating"); + null, null, hwProf, storageProfile, osProfile, networkProfile, diagnosticsProfile, VirtualMachineProperties.ProvisioningState.CREATING); return properties; } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApiMockTest.java index 99b0b57e77..79b48ef3db 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApiMockTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApiMockTest.java @@ -101,7 +101,7 @@ public class VirtualNetworkApiMockTest extends BaseAzureComputeApiMockTest { VirtualNetwork.AddressSpace.create(Arrays.asList("10.2.0.0/16")), null); - VirtualNetwork vn = vnApi.createOrUpdate(virtualNetwork, location, virtualNetworkProperties); + vnApi.createOrUpdate(virtualNetwork, location, virtualNetworkProperties); String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/virtualNetworks/%s?%s", subscriptionid, resourcegroup, virtualNetwork, apiVersion); String json = String.format("{\"location\":\"%s\",\"properties\":{\"addressSpace\":{\"addressPrefixes\":[\"%s\"]}}}", location, "10.2.0.0/16"); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/filters/ApiVersionFilterTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/filters/ApiVersionFilterTest.java new file mode 100644 index 0000000000..f3b15ce97c --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/filters/ApiVersionFilterTest.java @@ -0,0 +1,129 @@ +/* + * 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.filters; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.API_VERSION_PREFIX; +import static org.jclouds.reflect.Reflection2.method; +import static org.testng.Assert.assertEquals; + +import java.util.Properties; + +import javax.inject.Named; + +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.internal.FilterStringsBoundToInjectorByName; +import org.jclouds.reflect.Invocation; +import org.jclouds.rest.config.InvocationConfig; +import org.jclouds.rest.internal.GeneratedHttpRequest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.name.Names; + +@Test(groups = "unit", testName = "ApiVersionFilterTest", singleThreaded = true) +public class ApiVersionFilterTest { + + public interface VersionedApi { + HttpResponse noName(); + + @Named("named:get") + HttpResponse named(); + } + + private Invocation noName; + private Invocation named; + private InvocationConfig config; + + @BeforeMethod + public void setup() { + noName = Invocation.create(method(VersionedApi.class, "noName"), ImmutableList.of()); + named = Invocation.create(method(VersionedApi.class, "named"), ImmutableList.of()); + + config = createMock(InvocationConfig.class); + expect(config.getCommandName(noName)).andReturn("VersionedApi.noName"); + expect(config.getCommandName(named)).andReturn("named:get"); + replay(config); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testFailIfNoGeneratedHttpRequest() { + ApiVersionFilter filter = new ApiVersionFilter(config, filterStringsBoundToInjectorByName(new Properties())); + filter.filter(HttpRequest.builder().method("GET").endpoint("http://localhost").build()); + } + + @Test + public void testOverrideMethodVersion() { + Properties props = new Properties(); + props.setProperty(API_VERSION_PREFIX + "named:get", "namedversion"); + props.setProperty(API_VERSION_PREFIX + "VersionedApi.noName", "noNameversion"); + ApiVersionFilter filter = new ApiVersionFilter(config, filterStringsBoundToInjectorByName(props)); + + HttpRequest request = GeneratedHttpRequest.builder().method("GET").endpoint("http://localhost") + .invocation(noName).addQueryParam("api-version", "original", "original2").build(); + HttpRequest filtered = filter.filter(request); + assertEquals(filtered.getEndpoint().getQuery(), "api-version=noNameversion"); + + request = GeneratedHttpRequest.builder().method("GET").endpoint("http://localhost").invocation(named) + .addQueryParam("api-version", "original", "original2").build(); + filtered = filter.filter(request); + assertEquals(filtered.getEndpoint().getQuery(), "api-version=namedversion"); + } + + @Test + public void testFallbackToClassName() { + Properties props = new Properties(); + props.setProperty(API_VERSION_PREFIX + "VersionedApi", "classversion"); + ApiVersionFilter filter = new ApiVersionFilter(config, filterStringsBoundToInjectorByName(props)); + + HttpRequest request = GeneratedHttpRequest.builder().method("GET").endpoint("http://localhost") + .invocation(noName).addQueryParam("api-version", "original", "original2").build(); + HttpRequest filtered = filter.filter(request); + assertEquals(filtered.getEndpoint().getQuery(), "api-version=classversion"); + + request = GeneratedHttpRequest.builder().method("GET").endpoint("http://localhost").invocation(named) + .addQueryParam("api-version", "original", "original2").build(); + filtered = filter.filter(request); + assertEquals(filtered.getEndpoint().getQuery(), "api-version=classversion"); + } + + @Test + public void testNothingChangesIfNoCustomVersion() { + ApiVersionFilter filter = new ApiVersionFilter(config, filterStringsBoundToInjectorByName(new Properties())); + + HttpRequest request = GeneratedHttpRequest.builder().method("GET").endpoint("http://localhost").invocation(named) + .addQueryParam("api-version", "foo").build(); + HttpRequest filtered = filter.filter(request); + assertEquals(filtered.getEndpoint().getQuery(), "api-version=foo"); + } + + private FilterStringsBoundToInjectorByName filterStringsBoundToInjectorByName(final Properties props) { + Injector injector = Guice.createInjector(new AbstractModule() { + protected void configure() { + Names.bindProperties(binder(), props); + } + }); + return new FilterStringsBoundToInjectorByName(injector); + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiMockTest.java index 82af9789a7..dc4ad28cf6 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiMockTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiMockTest.java @@ -28,6 +28,7 @@ import org.jclouds.ContextBuilder; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; import org.jclouds.concurrent.config.ExecutorServiceModule; +import org.jclouds.rest.ApiContext; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; @@ -50,6 +51,7 @@ public class BaseAzureComputeApiMockTest { protected MockWebServer server; protected AzureComputeApi api; + protected ApiContext context; // So that we can ignore formatting. private final JsonParser parser = new JsonParser(); @@ -58,16 +60,21 @@ public class BaseAzureComputeApiMockTest { public void start() throws IOException { server = new MockWebServer(); server.play(); - Properties properties = new Properties(); - properties.put(CREDENTIAL_TYPE, BEARER_TOKEN_CREDENTIALS.toString()); - properties.put("oauth.endpoint", "https://login.microsoftonline.com/tenant-id/oauth2/token"); AzureComputeProviderMetadata pm = AzureComputeProviderMetadata.builder().build(); - api = ContextBuilder.newBuilder(pm) + context = ContextBuilder.newBuilder(pm) .credentials("", MOCK_BEARER_TOKEN) .endpoint(server.getUrl("/").toString() + "subscriptions/SUBSCRIPTIONID") .modules(modules) - .overrides(properties) - .buildApi(AzureComputeApi.class); + .overrides(setupProperties()) + .build(); + api = context.getApi(); + } + + protected Properties setupProperties() { + Properties properties = new Properties(); + properties.put(CREDENTIAL_TYPE, BEARER_TOKEN_CREDENTIALS.toString()); + properties.put("oauth.endpoint", "https://login.microsoftonline.com/tenant-id/oauth2/token"); + return properties; } @AfterMethod(alwaysRun = true)