JCLOUDS-664 Azurecompute-arm compute service
Project: http://git-wip-us.apache.org/repos/asf/jclouds-labs/repo Commit: http://git-wip-us.apache.org/repos/asf/jclouds-labs/commit/03f72d5e Tree: http://git-wip-us.apache.org/repos/asf/jclouds-labs/tree/03f72d5e Diff: http://git-wip-us.apache.org/repos/asf/jclouds-labs/diff/03f72d5e Branch: refs/heads/master Commit: 03f72d5e2f225f212d05151c1c15a99af14cd29e Parents: e4cbe22 Author: Rita Zhang <[email protected]> Authored: Mon May 16 18:55:01 2016 -0700 Committer: Ignasi Barrera <[email protected]> Committed: Fri Jun 17 22:24:32 2016 +0200 ---------------------------------------------------------------------- azurecompute-arm/README.md | 20 +- .../azurecompute/arm/AzureComputeApi.java | 11 +- .../arm/AzureComputeProviderMetadata.java | 21 +- .../arm/AzureManagementApiMetadata.java | 2 + .../arm/compute/AzureComputeService.java | 104 +++++ .../arm/compute/AzureComputeServiceAdapter.java | 393 +++++++++++++++++++ .../AzureComputeServiceContextModule.java | 191 +++++++++ .../functions/DeploymentToNodeMetadata.java | 207 ++++++++++ .../compute/functions/LocationToLocation.java | 7 +- .../compute/functions/VMHardwareToHardware.java | 79 ++++ .../arm/compute/functions/VMImageToImage.java | 124 ++++++ .../CreateResourceGroupThenCreateNodes.java | 96 +++++ .../arm/config/AzureComputeProperties.java | 8 + .../arm/domain/ResourceProviderMetaData.java | 68 ++++ .../azurecompute/arm/domain/VMDeployment.java | 2 + .../azurecompute/arm/domain/VMHardware.java | 68 ++++ .../azurecompute/arm/domain/VMImage.java | 53 +++ .../azurecompute/arm/domain/VirtualMachine.java | 2 +- .../arm/features/ResourceProviderApi.java | 57 +++ .../arm/functions/CleanupResources.java | 107 +++++ .../arm/util/DeploymentTemplateBuilder.java | 31 +- .../AzureComputeServiceContextLiveTest.java | 284 ++++++++++++++ .../compute/AzureComputeServiceLiveTest.java | 73 ++++ .../compute/AzureTemplateBuilderLiveTest.java | 77 ++++ .../features/ResourceProviderAPIMockTest.java | 67 ++++ .../features/ResourceProviderApiLiveTest.java | 55 +++ .../AbstractAzureComputeApiLiveTest.java | 24 +- .../internal/BaseAzureComputeApiLiveTest.java | 19 - .../resources/getresourceprovidermetadata.json | 366 +++++++++++++++++ 29 files changed, 2564 insertions(+), 52 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/03f72d5e/azurecompute-arm/README.md ---------------------------------------------------------------------- diff --git a/azurecompute-arm/README.md b/azurecompute-arm/README.md index fc8bb54..c944a8a 100644 --- a/azurecompute-arm/README.md +++ b/azurecompute-arm/README.md @@ -53,13 +53,25 @@ azure login -u <Application-id> -p <password> --service-principal --tenant <Tena ## Run Live Tests -Use the following to run the live tests +Use the following to run one live test: + +```bash +mvn -Dtest=<name of the live test> \ + -Dtest.azurecompute-arm.identity="<Application-id>" \ + -Dtest.azurecompute-arm.credential="<password>" \ + -Dtest.azurecompute-arm.endpoint="https://management.azure.com/subscriptions/<Subscription-id>" \ + -Dtest.oauth.endpoint="https://login.microsoftonline.com/<Tenant-id>/oauth2/token" test + +``` + +Use the following to run all the live tests: ```bash mvn clean verify -Plive \ - -Dtest.azurecompute-arm.identity=<Application-id> \ - -Dtest.azurecompute-arm.credential=<password> \ - -Dtest.azurecompute-arm.endpoint=https://management.azure.com/subscriptions/<Subscription-id> \ + -Dtest.azurecompute-arm.identity="<Application-id>"" \ + -Dtest.azurecompute-arm.credential="<password>"" \ + -Dtest.azurecompute-arm.endpoint="https://management.azure.com/subscriptions/<Subscription-id>"" \ -Dtest.oauth.endpoint=https://login.microsoftonline.com/<Tenant-id>/oauth2/token + ``` http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/03f72d5e/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeApi.java ---------------------------------------------------------------------- diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeApi.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeApi.java index c39022e..42749cf 100644 --- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeApi.java +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeApi.java @@ -17,18 +17,19 @@ package org.jclouds.azurecompute.arm; 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.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.VirtualMachineApi; import org.jclouds.azurecompute.arm.features.VirtualNetworkApi; import org.jclouds.azurecompute.arm.features.VMSizeApi; -import org.jclouds.azurecompute.arm.util.DeploymentTemplateBuilder; import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi; import org.jclouds.azurecompute.arm.features.NetworkSecurityRuleApi; import org.jclouds.rest.annotations.Delegate; @@ -156,6 +157,14 @@ public interface AzureComputeApi extends Closeable { NetworkSecurityRuleApi getNetworkSecurityRuleApi(@PathParam("resourcegroup") String resourcegroup, @PathParam("networksecuritygroup") String networksecuritygroup); + /** + * The Azure Resource Provider API provides information about a resource provider and its supported resource types. + * + * @see <a href="https://msdn.microsoft.com/en-us/library/azure/dn790534.aspx">docs</a> + */ + @Delegate + ResourceProviderApi getResourceProviderApi(); + @Provides DeploymentTemplateBuilder.Factory deploymentTemplateFactory(); } http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/03f72d5e/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeProviderMetadata.java ---------------------------------------------------------------------- diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeProviderMetadata.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeProviderMetadata.java index 39defdc..4bbc508 100644 --- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeProviderMetadata.java +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeProviderMetadata.java @@ -16,11 +16,17 @@ */ package org.jclouds.azurecompute.arm; + +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.TCP_RULE_FORMAT; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TCP_RULE_REGEXP; + +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_IMAGE_LOGIN; + 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; @@ -30,6 +36,9 @@ import java.util.Properties; import org.jclouds.azurecompute.arm.domain.Region; 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; @@ -51,13 +60,19 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { public static Properties defaultProperties() { final Properties properties = AzureManagementApiMetadata.defaultProperties(); - properties.setProperty(OPERATION_TIMEOUT, "60000"); + properties.put(ComputeServiceProperties.POLL_INITIAL_PERIOD, 1000); + properties.put(ComputeServiceProperties.POLL_MAX_PERIOD, 10000); + properties.setProperty(OPERATION_TIMEOUT, "46000000"); properties.setProperty(OPERATION_POLL_INITIAL_PERIOD, "5"); properties.setProperty(OPERATION_POLL_MAX_PERIOD, "15"); properties.setProperty(TCP_RULE_FORMAT, "tcp_%s-%s"); properties.setProperty(TCP_RULE_REGEXP, "tcp_\\d{1,5}-\\d{1,5}"); - properties.put(RESOURCE, "https://management.azure.com"); + properties.put(RESOURCE, "https://management.azure.com/"); properties.put(CREDENTIAL_TYPE, CLIENT_CREDENTIALS_SECRET.toString()); + properties.put(RESOURCE_GROUP_NAME, "jcloudsgroup"); + properties.put(IMAGE_PUBLISHERS, "Microsoft.WindowsAzure.Compute, MicrosoftWindowsServer, Canonical"); + properties.put(DEFAULT_IMAGE_LOGIN, "jclouds:Password1!"); + properties.put(TIMEOUT_NODE_TERMINATED, 60 * 10 * 1000); return properties; } http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/03f72d5e/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java ---------------------------------------------------------------------- diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java index 9a3292c..989fd84 100644 --- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java @@ -26,6 +26,7 @@ import org.jclouds.azurecompute.arm.config.AzureComputeHttpApiModule; import org.jclouds.compute.ComputeServiceContext; import org.jclouds.rest.internal.BaseHttpApiMetadata; import org.jclouds.oauth.v2.config.OAuthModule; +import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule; import com.google.common.collect.ImmutableSet; import com.google.inject.Module; @@ -68,6 +69,7 @@ public class AzureManagementApiMetadata extends BaseHttpApiMetadata<AzureCompute .defaultProperties(AzureManagementApiMetadata.defaultProperties()) .view(typeToken(ComputeServiceContext.class)) .defaultModules(ImmutableSet.<Class<? extends Module>>builder() + .add(AzureComputeServiceContextModule.class) .add(OAuthModule.class) .add(OkHttpCommandExecutorServiceModule.class) .add(AzureComputeHttpApiModule.class).build()); http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/03f72d5e/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java ---------------------------------------------------------------------- diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java new file mode 100644 index 0000000..c215e37 --- /dev/null +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java @@ -0,0 +1,104 @@ +/* + * 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; + +import static com.google.common.base.Preconditions.checkNotNull; +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 java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Provider; +import javax.inject.Singleton; + +import org.jclouds.Constants; +import org.jclouds.collect.Memoized; +import org.jclouds.compute.ComputeServiceContext; +import org.jclouds.compute.callables.RunScriptOnNode; +import org.jclouds.compute.domain.Hardware; +import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.TemplateBuilder; +import org.jclouds.compute.extensions.ImageExtension; +import org.jclouds.compute.extensions.SecurityGroupExtension; +import org.jclouds.compute.internal.BaseComputeService; +import org.jclouds.compute.internal.PersistNodeCredentials; +import org.jclouds.compute.options.TemplateOptions; +import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; +import org.jclouds.compute.strategy.CreateNodesInGroupThenAddToSet; +import org.jclouds.compute.strategy.DestroyNodeStrategy; +import org.jclouds.compute.strategy.GetImageStrategy; +import org.jclouds.compute.strategy.GetNodeMetadataStrategy; +import org.jclouds.compute.strategy.InitializeRunScriptOnNodeOrPlaceInBadMap; +import org.jclouds.compute.strategy.ListNodesStrategy; +import org.jclouds.compute.strategy.RebootNodeStrategy; +import org.jclouds.compute.strategy.ResumeNodeStrategy; +import org.jclouds.compute.strategy.SuspendNodeStrategy; +import org.jclouds.domain.Credentials; +import org.jclouds.domain.Location; +import org.jclouds.azurecompute.arm.functions.CleanupResources; +import org.jclouds.scriptbuilder.functions.InitAdminAccess; + +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; +import com.google.common.util.concurrent.ListeningExecutorService; + +@Singleton +public class AzureComputeService extends BaseComputeService { + protected final CleanupResources cleanupResources; + + @Inject + protected AzureComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore, + @Memoized Supplier<Set<? extends Image>> images, @Memoized Supplier<Set<? extends Hardware>> sizes, + @Memoized Supplier<Set<? extends Location>> locations, ListNodesStrategy listNodesStrategy, + GetImageStrategy getImageStrategy, GetNodeMetadataStrategy getNodeMetadataStrategy, + CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, RebootNodeStrategy rebootNodeStrategy, + DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy startNodeStrategy, + SuspendNodeStrategy stopNodeStrategy, Provider<TemplateBuilder> templateBuilderProvider, + @Named("DEFAULT") Provider<TemplateOptions> templateOptionsProvider, + @Named(TIMEOUT_NODE_RUNNING) Predicate<AtomicReference<NodeMetadata>> nodeRunning, + @Named(TIMEOUT_NODE_TERMINATED) Predicate<AtomicReference<NodeMetadata>> nodeTerminated, + @Named(TIMEOUT_NODE_SUSPENDED) Predicate<AtomicReference<NodeMetadata>> nodeSuspended, + InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, + RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, + PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, + @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, + CleanupResources cleanupResources, + Optional<ImageExtension> imageExtension, + Optional<SecurityGroupExtension> securityGroupExtension) { + super(context, credentialStore, images, sizes, locations, listNodesStrategy, getImageStrategy, + getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, + startNodeStrategy, stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, + nodeTerminated, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, + persistNodeCredentials, timeouts, userExecutor, imageExtension, securityGroupExtension); + this.cleanupResources = checkNotNull(cleanupResources, "cleanupResources"); + + } + + @Override + protected void cleanUpIncidentalResourcesOfDeadNodes(Set<? extends NodeMetadata> deadNodes) { + for (NodeMetadata deadNode : deadNodes) { + cleanupResources.apply(deadNode.getId()); + } + } + +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/03f72d5e/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java ---------------------------------------------------------------------- diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java new file mode 100644 index 0000000..9a1d221 --- /dev/null +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java @@ -0,0 +1,393 @@ +/* + * 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; + +import static java.lang.String.format; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.jclouds.util.Predicates2.retry; +import java.util.ArrayList; + +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 com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; +import com.google.common.net.UrlEscapers; +import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.AzureComputeConstants; +import org.jclouds.azurecompute.arm.compute.functions.VMImageToImage; +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.VMImage; +import org.jclouds.azurecompute.arm.domain.VMHardware; +import org.jclouds.azurecompute.arm.domain.Location; +import org.jclouds.azurecompute.arm.domain.Offer; +import org.jclouds.azurecompute.arm.domain.PublicIPAddress; +import org.jclouds.azurecompute.arm.domain.ResourceProviderMetaData; +import org.jclouds.azurecompute.arm.domain.SKU; +import org.jclouds.azurecompute.arm.domain.VMDeployment; +import org.jclouds.azurecompute.arm.domain.VMSize; +import org.jclouds.azurecompute.arm.domain.VirtualMachine; +import org.jclouds.azurecompute.arm.features.DeploymentApi; +import org.jclouds.azurecompute.arm.features.OSImageApi; +import org.jclouds.azurecompute.arm.features.VirtualMachineApi; +import org.jclouds.azurecompute.arm.util.DeploymentTemplateBuilder; +import org.jclouds.compute.ComputeServiceAdapter; +import org.jclouds.compute.domain.Template; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.domain.LoginCredentials; +import org.jclouds.logging.Logger; +import org.jclouds.azurecompute.arm.functions.CleanupResources; + +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.google.common.base.Splitter; +import static com.google.common.base.Preconditions.checkState; + +/** + * Defines the connection between the {@link AzureComputeApi} implementation and the jclouds + * {@link org.jclouds.compute.ComputeService}. + */ +@Singleton +public class AzureComputeServiceAdapter implements ComputeServiceAdapter<VMDeployment, VMHardware, VMImage, Location> { + + private String azureGroup; + protected final CleanupResources cleanupResources; + + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + private Logger logger = Logger.NULL; + + private final AzureComputeApi api; + + private final AzureComputeConstants azureComputeConstants; + + @Inject + AzureComputeServiceAdapter(final AzureComputeApi api, final AzureComputeConstants azureComputeConstants, + CleanupResources cleanupResources) { + + this.api = api; + this.azureComputeConstants = azureComputeConstants; + + this.azureGroup = azureComputeConstants.azureResourceGroup(); + + logger.debug("AzureComputeServiceAdapter set azuregroup to: " + azureGroup); + + this.cleanupResources = cleanupResources; + } + + @Override + public NodeAndInitialCredentials<VMDeployment> createNodeWithGroupEncodedIntoName( + final String group, final String name, final Template template) { + + DeploymentTemplateBuilder deploymentTemplateBuilder = api.deploymentTemplateFactory().create(group, name, template); + + final String loginUser = DeploymentTemplateBuilder.getLoginUserUsername(); + final String loginPassword = DeploymentTemplateBuilder.getLoginPassword(); + + DeploymentBody deploymentTemplateBody = deploymentTemplateBuilder.getDeploymentTemplate(); + + 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<VMDeployment> deployments = Sets.newHashSet(); + + final DeploymentApi deploymentApi = api.getDeploymentApi(group); + + if (!retry(new Predicate<String>() { + @Override + public boolean apply(final String name) { + + Deployment deployment = deploymentApi.create(name, deploymentTemplate); + + if (deployment != null) { + VMDeployment vmDeployment = new VMDeployment(); + vmDeployment.deployment = 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(); + + + return new NodeAndInitialCredentials<VMDeployment>(deployment, name, + LoginCredentials.builder().user(loginUser).identity(loginUser).password(loginPassword).authenticateSudo(true).build()); + } + + @Override + public Iterable<VMHardware> listHardwareProfiles() { + + final List<VMHardware> hwProfiles = Lists.newArrayList(); + final List<String> locationIds = Lists.newArrayList(); + + Iterable<Location> locations = listLocations(); + for (Location location : locations){ + locationIds.add(location.name()); + + Iterable<VMSize> vmSizes = api.getVMSizeApi(location.name()).list(); + + for (VMSize vmSize : vmSizes){ + VMHardware hwProfile = new VMHardware(); + hwProfile.name = vmSize.name(); + hwProfile.numberOfCores = vmSize.numberOfCores(); + hwProfile.osDiskSizeInMB = vmSize.osDiskSizeInMB(); + hwProfile.resourceDiskSizeInMB = vmSize.resourceDiskSizeInMB(); + hwProfile.memoryInMB = vmSize.memoryInMB(); + hwProfile.maxDataDiskCount = vmSize.maxDataDiskCount(); + hwProfile.location = location.name(); + hwProfiles.add(hwProfile); + } + + } + + checkAndSetHwAvailability(hwProfiles, Sets.newHashSet(locationIds)); + + return hwProfiles; + } + private void checkAndSetHwAvailability(List<VMHardware> hwProfiles, Collection<String> locations) { + Multimap<String, String> hwMap = ArrayListMultimap.create(); + for (VMHardware hw : hwProfiles) { + hwMap.put(hw.name, hw.location); + } + + for (VMHardware hw : hwProfiles) { + hw.globallyAvailable = hwMap.get(hw.name).containsAll(locations); + } + } + + private void getImagesFromPublisher(String publisherName, List<VMImage> osImagesRef, String location) { + + OSImageApi osImageApi = api.getOSImageApi(location); + + Iterable<Offer> offerList = osImageApi.listOffers(publisherName); + + for (Offer offer : offerList) { + Iterable<SKU> skuList = osImageApi.listSKUs(publisherName, offer.name()); + + for (SKU sku : skuList) { + VMImage vmImage = new VMImage(); + vmImage.publisher = publisherName; + vmImage.offer = offer.name(); + vmImage.sku = sku.name(); + vmImage.location = location; + osImagesRef.add(vmImage); + } + } + } + + private List<VMImage> listImagesByLocation(String location) { + final List<VMImage> osImages = Lists.newArrayList(); + Iterable<String> publishers = Splitter.on(',').trimResults().omitEmptyStrings().split(this.azureComputeConstants.azureImagePublishers()); + for (String publisher : publishers) { + getImagesFromPublisher(publisher, osImages, location); + } + return osImages; + } + + @Override + public Iterable<VMImage> listImages() { + + final List<VMImage> osImages = Lists.newArrayList(); + final List<String> locationIds = Lists.newArrayList(); + + for (Location location : listLocations()){ + locationIds.add(location.name()); + osImages.addAll(listImagesByLocation(location.name())); + } + checkAndSetImageAvailability(osImages, Sets.newHashSet(locationIds)); + return osImages; + } + + private void checkAndSetImageAvailability(List<VMImage> images, Collection<String> locations) { + Multimap<String, String> map = ArrayListMultimap.create(); + + for (VMImage image : images) { + map.put( image.offer + "/" + image.sku, image.location); + } + + for (VMImage image : images) { + image.globallyAvailable = map.get(image.offer + "/" + image.sku).containsAll(locations); + } + } + + @Override + public VMImage getImage(final String id) { + String[] fields = VMImageToImage.decodeFieldsFromUniqueId(id); + + Iterable<VMImage> images = listImages(); + + for (VMImage image : images) { + String imageId = VMImageToImage.encodeFieldsToUniqueId(image); + if (id.equals(imageId)){ + return image; + } + } + return null; + } + + @Override + public Iterable<Location> listLocations() { + List<Location> locations = api.getLocationApi().list(); + + List<ResourceProviderMetaData> resources = api.getResourceProviderApi().get("Microsoft.Compute"); + + final List<String> vmLocations = new ArrayList<String>(); + + for (ResourceProviderMetaData m : resources){ + if (m.resourceType().equals("virtualMachines")){ + vmLocations.addAll(m.locations()); + break; + } + } + + Iterable<Location> result = Iterables.filter(locations, new Predicate<Location>() { + @Override + public boolean apply(Location input) { + return vmLocations.contains(input.displayName()); + } + }); + + return result; + } + + 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; + } + + @Override + public VMDeployment getNode(final String id) { + Deployment deployment = api.getDeploymentApi(azureGroup).get(id); + if (deployment == null) + return null; + String resourceGroup = getResourceGroupFromId(deployment.id()); + VMDeployment vmDeployment = new VMDeployment(); + vmDeployment.deployment = deployment; + List<PublicIPAddress> list = getIPAddresses(deployment); + vmDeployment.ipAddressList = list; + + VirtualMachine vm = api.getVirtualMachineApi(azureGroup).get(id); + vmDeployment.virtualMachine = vm; + return vmDeployment; + } + + @Override + public void destroyNode(final String id) { + checkState(cleanupResources.apply(id), "server(%s) and its resources still there after deleting!?", id); + } + + @Override + public void rebootNode(final String id) { + api.getVirtualMachineApi(azureGroup).restart(id); + } + + @Override + public void resumeNode(final String id) { + api.getVirtualMachineApi(azureGroup).start(id); + } + + @Override + public void suspendNode(final String id) { + api.getVirtualMachineApi(azureGroup).stop(id); + } + + private List<PublicIPAddress> getIPAddresses(Deployment deployment) { + List<PublicIPAddress> list = new ArrayList<PublicIPAddress>(); + String resourceGroup = getResourceGroupFromId(deployment.id()); + + if (deployment.properties() != null && deployment.properties().dependencies() != null) { + List<Deployment.Dependency> dependencies = deployment.properties().dependencies(); + for (int d = 0; d < dependencies.size(); d++) { + if (dependencies.get(d).resourceType().equals("Microsoft.Network/networkInterfaces")) { + List<Deployment.Dependency> 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; + } + + @Override + public Iterable<VMDeployment> listNodes() { + List<Deployment> deployments = api.getDeploymentApi(azureGroup).list(); + + List<VMDeployment> vmDeployments = new ArrayList<VMDeployment>(); + + for (Deployment d : deployments){ + VMDeployment vmDeployment = new VMDeployment(); + vmDeployment.deployment = d; + VirtualMachineApi vmApi = api.getVirtualMachineApi(azureGroup); + vmDeployment.vm = vmApi.getInstanceDetails(d.name()); + List<PublicIPAddress> list = getIPAddresses(d); + vmDeployment.ipAddressList = list; + + VirtualMachine virtualMachine = vmApi.get(d.name()); + vmDeployment.virtualMachine = virtualMachine; + + vmDeployments.add(vmDeployment); + } + return vmDeployments; + } + + @Override + public Iterable<VMDeployment> listNodesByIds(final Iterable<String> ids) { + return Iterables.filter(listNodes(), new Predicate<VMDeployment>() { + @Override + public boolean apply(final VMDeployment input) { + return Iterables.contains(ids, input.deployment.name()); + } + }); + } + +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/03f72d5e/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/config/AzureComputeServiceContextModule.java ---------------------------------------------------------------------- diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/config/AzureComputeServiceContextModule.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/config/AzureComputeServiceContextModule.java new file mode 100644 index 0000000..9844be4 --- /dev/null +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/config/AzureComputeServiceContextModule.java @@ -0,0 +1,191 @@ +/* + * 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.config; + +import javax.inject.Named; +import javax.inject.Singleton; +import com.google.inject.Provides; + +import org.jclouds.azurecompute.arm.compute.AzureComputeServiceAdapter; +import org.jclouds.azurecompute.arm.compute.functions.VMImageToImage; +import org.jclouds.azurecompute.arm.compute.functions.DeploymentToNodeMetadata; +import org.jclouds.azurecompute.arm.compute.functions.VMHardwareToHardware; +import org.jclouds.azurecompute.arm.compute.functions.LocationToLocation; +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.Location; +import org.jclouds.azurecompute.arm.compute.strategy.CreateResourceGroupThenCreateNodes; +import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.functions.ParseJobStatus; +import org.jclouds.azurecompute.arm.compute.AzureComputeService; + +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.strategy.CreateNodesInGroupThenAddToSet; +import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; +import org.jclouds.compute.reference.ComputeServiceConstants.PollPeriod; +import org.jclouds.compute.ComputeService; +import static org.jclouds.util.Predicates2.retry; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED; + +import com.google.common.base.Function; +import com.google.inject.Inject; +import com.google.inject.TypeLiteral; +import com.google.common.base.Predicate; +import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.annotations.VisibleForTesting; +import java.net.URI; + + +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.TCP_RULE_FORMAT; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TCP_RULE_REGEXP; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_IMAGE_LOGIN; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; + +public class AzureComputeServiceContextModule + extends ComputeServiceAdapterContextModule<VMDeployment, VMHardware, VMImage, Location> { + + @Override + protected void configure() { + super.configure(); + bind(new TypeLiteral<ComputeServiceAdapter<VMDeployment, VMHardware, VMImage, Location>>() { + }).to(AzureComputeServiceAdapter.class); + bind(new TypeLiteral<Function<VMImage, org.jclouds.compute.domain.Image>>() { + }).to(VMImageToImage.class); + bind(new TypeLiteral<Function<VMHardware, Hardware>>() { + }).to(VMHardwareToHardware.class); + bind(new TypeLiteral<Function<VMDeployment, NodeMetadata>>() { + }).to(DeploymentToNodeMetadata.class); + bind(new TypeLiteral<Function<Location, org.jclouds.domain.Location>>() { + }).to(LocationToLocation.class); + bind(ComputeService.class).to(AzureComputeService.class); + install(new LocationsFromComputeServiceAdapterModule<VMDeployment, VMHardware, VMImage, Location>() { + }); + + bind(CreateNodesInGroupThenAddToSet.class).to(CreateResourceGroupThenCreateNodes.class); + } + + @Singleton + public static class AzureComputeConstants { + + @Named(OPERATION_TIMEOUT) + @Inject + private String operationTimeoutProperty; + + @Named(OPERATION_POLL_INITIAL_PERIOD) + @Inject + private String operationPollInitialPeriodProperty; + + @Named(OPERATION_POLL_MAX_PERIOD) + @Inject + private String operationPollMaxPeriodProperty; + + @Named(TCP_RULE_FORMAT) + @Inject + private String tcpRuleFormatProperty; + + @Named(TCP_RULE_REGEXP) + @Inject + private String tcpRuleRegexpProperty; + + @Named(RESOURCE_GROUP_NAME) + @Inject + private String azureResourceGroupProperty; + + @Named(IMAGE_PUBLISHERS) + @Inject + private String azureImagePublishersProperty; + + @Named(DEFAULT_IMAGE_LOGIN) + @Inject + private String azureDefaultImageLoginProperty; + + public Long operationTimeout() { + return Long.parseLong(operationTimeoutProperty); + } + + public String azureResourceGroup() { + return azureResourceGroupProperty; + } + + public String azureImagePublishers() { + return azureImagePublishersProperty; + } + + public String azureDefaultImageLogin() { + return azureDefaultImageLoginProperty; + } + + public Integer operationPollInitialPeriod() { + return Integer.parseInt(operationPollInitialPeriodProperty); + } + + public Integer operationPollMaxPeriod() { + return Integer.parseInt(operationPollMaxPeriodProperty); + } + + public String tcpRuleFormat() { + return tcpRuleFormatProperty; + } + + public String tcpRuleRegexp() { + return tcpRuleRegexpProperty; + } + } + + @Provides + @Named(TIMEOUT_NODE_TERMINATED) + protected Predicate<URI> provideNodeTerminatedPredicate(final AzureComputeApi api, Timeouts timeouts, + PollPeriod pollPeriod) { + return retry(new ActionDonePredicate(api), timeouts.nodeTerminated, pollPeriod.pollInitialPeriod, + pollPeriod.pollMaxPeriod); + } + + @Provides + @Named(TIMEOUT_RESOURCE_DELETED) + protected Predicate<URI> provideResourceDeletedPredicate(final AzureComputeApi api, Timeouts timeouts, + PollPeriod pollPeriod) { + return retry(new ActionDonePredicate(api), timeouts.nodeTerminated, pollPeriod.pollInitialPeriod, + pollPeriod.pollMaxPeriod); + } + + @VisibleForTesting + static class ActionDonePredicate implements Predicate<URI> { + + private final AzureComputeApi api; + + public ActionDonePredicate(AzureComputeApi api) { + this.api = checkNotNull(api, "api must not be null"); + } + + @Override + public boolean apply(URI uri) { + checkNotNull(uri, "uri cannot be null"); + return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri); + } + + } + +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/03f72d5e/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/DeploymentToNodeMetadata.java ---------------------------------------------------------------------- diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/DeploymentToNodeMetadata.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/DeploymentToNodeMetadata.java new file mode 100644 index 0000000..bccc63c --- /dev/null +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/DeploymentToNodeMetadata.java @@ -0,0 +1,207 @@ +/* + * 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.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<VMDeployment, NodeMetadata> { + + public static final String AZURE_LOGIN_USERNAME = DeploymentTemplateBuilder.getLoginUserUsername(); + public static final String AZURE_LOGIN_PASSWORD = DeploymentTemplateBuilder.getLoginPassword(); + + private static final Map<ComputeNode.Status, NodeMetadata.Status> INSTANCESTATUS_TO_NODESTATUS = + ImmutableMap.<ComputeNode.Status, NodeMetadata.Status>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<Deployment.ProvisioningState, NodeMetadata.Status> STATUS_TO_NODESTATUS = + ImmutableMap.<Deployment.ProvisioningState, NodeMetadata.Status>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<String, Credentials> credentialStore; + + @Inject + DeploymentToNodeMetadata( + AzureComputeApi api, + LocationToLocation locationToLocation, + GroupNamingConvention.Factory namingConvention, VMImageToImage vmImageToImage, + VMHardwareToHardware vmHardwareToHardware, Map<String, Credentials> 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); + + NodeMetadata.Status status = STATUS_TO_NODESTATUS.get(provisioningStateFromString(deployment.properties().provisioningState())); + if (status == NodeMetadata.Status.RUNNING && from.vm != null && from.vm.statuses() != null) { + List<VirtualMachineInstance.VirtualMachineStatus> 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); + + Credentials credentials = credentialStore.get("node#" + from.deployment.name()); + if (credentials == null) { + credentials = new Credentials(AZURE_LOGIN_USERNAME, AZURE_LOGIN_PASSWORD); + } + builder.credentials(LoginCredentials.fromCredentials(credentials)); + + final Set<String> 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); + } + + org.jclouds.azurecompute.arm.domain.Location myLocation = null; + if (from.virtualMachine != null) { + String locationName = from.virtualMachine.location(); + List<org.jclouds.azurecompute.arm.domain.Location> 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(); + + VMImage vmImage = new VMImage(); + vmImage.publisher = imageReference.publisher(); + vmImage.offer = imageReference.offer(); + vmImage.sku = imageReference.sku(); + vmImage.location = locationName; + Image image = vmImageToImage.apply(vmImage); + builder.imageId(image.getId()); + + VMSize myVMSize = null; + String vmSizeName = from.virtualMachine.properties().hardwareProfile().vmSize(); + List<VMSize> vmSizes = api.getVMSizeApi(locationName).list(); + for (VMSize vmSize : vmSizes) { + if (vmSize.name().equals(vmSizeName)) { + myVMSize = vmSize; + break; + } + } + + VMHardware hwProfile = new VMHardware(); + hwProfile.name = myVMSize.name(); + hwProfile.numberOfCores = myVMSize.numberOfCores(); + hwProfile.osDiskSizeInMB = myVMSize.osDiskSizeInMB(); + hwProfile.resourceDiskSizeInMB = myVMSize.resourceDiskSizeInMB(); + hwProfile.memoryInMB = myVMSize.memoryInMB(); + hwProfile.maxDataDiskCount = myVMSize.maxDataDiskCount(); + hwProfile.location = locationName; + + Hardware hardware = vmHardwareToHardware.apply(hwProfile); + builder.hardware(hardware); + } + + return builder.build(); + } +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/03f72d5e/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToLocation.java ---------------------------------------------------------------------- diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToLocation.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToLocation.java index a4d4b1e..0ca1458 100644 --- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToLocation.java +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToLocation.java @@ -38,6 +38,7 @@ public class LocationToLocation implements Function<Location, org.jclouds.domain private final JustProvider justProvider; + // allow us to lazy discover the provider of a resource @Inject LocationToLocation(JustProvider justProvider) { this.justProvider = justProvider; @@ -46,7 +47,11 @@ public class LocationToLocation implements Function<Location, org.jclouds.domain @Override public org.jclouds.domain.Location apply(final Location location) { final LocationBuilder builder = new LocationBuilder(); - builder.id(location.id()); + String id = location.id(); + int index = id.lastIndexOf('/'); + if (index > 0 && (index + 1) < id.length()) + id = id.substring(index + 1); + builder.id(id); builder.description(location.displayName()); builder.parent(getOnlyElement(justProvider.get())); http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/03f72d5e/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMHardwareToHardware.java ---------------------------------------------------------------------- diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMHardwareToHardware.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMHardwareToHardware.java new file mode 100644 index 0000000..51a6e5e --- /dev/null +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMHardwareToHardware.java @@ -0,0 +1,79 @@ +/* + * 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 com.google.common.base.Supplier; +import com.google.common.collect.FluentIterable; +import com.google.inject.Inject; +import org.jclouds.azurecompute.arm.domain.VMHardware; +import org.jclouds.collect.Memoized; +import org.jclouds.compute.domain.Hardware; +import org.jclouds.compute.domain.HardwareBuilder; +import org.jclouds.compute.domain.Processor; +import org.jclouds.compute.domain.Volume; +import org.jclouds.compute.domain.VolumeBuilder; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import org.jclouds.domain.Location; +import org.jclouds.location.predicates.LocationPredicates; + +import java.util.Set; + +public class VMHardwareToHardware implements Function<VMHardware, Hardware> { + + private final Supplier<Set<? extends Location>> locations; + + @Inject + VMHardwareToHardware(@Memoized final Supplier<Set<? extends Location>> locations) { + this.locations = locations; + } + + @Override + public Hardware apply(VMHardware from) { + final HardwareBuilder builder = new HardwareBuilder() + .name(from.name) + .id(from.name) + .processors(ImmutableList.of(new Processor(from.numberOfCores, 2))) + .ram(from.memoryInMB) + .location(from.globallyAvailable ? null : FluentIterable.from(locations.get()) + .firstMatch(LocationPredicates.idEquals(from.location)) + .get()); + + // No id or providerId from Azure + if (from.resourceDiskSizeInMB != null) { + builder.volume(new VolumeBuilder() + .size(Float.valueOf(from.resourceDiskSizeInMB)) + .type(Volume.Type.LOCAL) + .build()); + } + if (from.osDiskSizeInMB != null) { + builder.volume(new VolumeBuilder() + .size(Float.valueOf(from.osDiskSizeInMB)) + .type(Volume.Type.LOCAL) + .build()); + } + + ImmutableMap.Builder<String, String> metadata = ImmutableMap.builder(); + metadata.put("maxDataDiskCount", String.valueOf(from.maxDataDiskCount)); + builder.userMetadata(metadata.build()); + + return builder.build(); + } + +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/03f72d5e/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java ---------------------------------------------------------------------- diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java new file mode 100644 index 0000000..65a3d4b --- /dev/null +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java @@ -0,0 +1,124 @@ +/* + * 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 com.google.common.base.Supplier; +import com.google.common.collect.FluentIterable; +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.Location; +import org.jclouds.location.predicates.LocationPredicates; + +import java.util.Set; + +public class VMImageToImage implements Function<VMImage, Image> { + + 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 final Supplier<Set<? extends org.jclouds.domain.Location>> locations; + + public static String encodeFieldsToUniqueId(VMImage imageReference){ + return (imageReference.globallyAvailable ? "global" : imageReference.location) + "/" + imageReference.publisher + "/" + imageReference.offer + "/" + imageReference.sku; + } + + public static String[] decodeFieldsFromUniqueId(final String id) { + return checkNotNull(id, "id").split("/"); + } + + @Inject + VMImageToImage(@Memoized final Supplier<Set<? extends Location>> locations) { + this.locations = locations; + } + + @Override + public Image apply(final VMImage image) { + + final ImageBuilder builder = new ImageBuilder() + .name(image.offer) + .description(image.sku) + .status(Image.Status.AVAILABLE) + .version(image.sku) + .id(encodeFieldsToUniqueId(image)) + .providerId(image.publisher) + .location(image.globallyAvailable ? null : FluentIterable.from(locations.get()) + .firstMatch(LocationPredicates.idEquals(image.location)) + .get()); + + + final OperatingSystem.Builder osBuilder = osFamily().apply(image); + return builder.operatingSystem(osBuilder.build()).build(); + } + + public static Function<VMImage, OperatingSystem.Builder> osFamily() { + return new Function<VMImage, OperatingSystem.Builder>() { + @Override + public OperatingSystem.Builder apply(final VMImage image) { + checkNotNull(image.offer, "offer"); + final String label = image.offer; + + OsFamily family = OsFamily.UNRECOGNIZED; + if (label.contains(CENTOS)) { + family = OsFamily.CENTOS; + } else if (label.contains(OPENLOGIC)) { + family = OsFamily.CENTOS; + } else if (label.contains(SUSE)) { + family = OsFamily.SUSE; + } else if (label.contains(UBUNTU)) { + family = OsFamily.UBUNTU; + } else if (label.contains(WINDOWS)) { + family = OsFamily.WINDOWS; + } else if (label.contains(ORACLE_lINUX)) { + family = OsFamily.OEL; + } + + // only 64bit OS images are supported by Azure ARM + return OperatingSystem.builder(). + family(family). + is64Bit(true). + description(image.sku). + version(image.sku); + } + }; + } +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/03f72d5e/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourceGroupThenCreateNodes.java ---------------------------------------------------------------------- diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourceGroupThenCreateNodes.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourceGroupThenCreateNodes.java new file mode 100644 index 0000000..6900f17 --- /dev/null +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourceGroupThenCreateNodes.java @@ -0,0 +1,96 @@ +/* + * 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 static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Map; +import java.util.Set; + +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.domain.ResourceGroup; +import org.jclouds.azurecompute.arm.features.ResourceGroupApi; +import org.jclouds.compute.config.CustomizationResponse; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.Template; +import org.jclouds.compute.functions.GroupNamingConvention; +import org.jclouds.compute.reference.ComputeServiceConstants; +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.logging.Logger; +import com.google.common.collect.Multimap; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; + +@Singleton +public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEncodedIntoNameThenAddToSet { + + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + private final AzureComputeApi api; + + @Inject + protected CreateResourceGroupThenCreateNodes( + CreateNodeWithGroupEncodedIntoName addNodeWithGroupStrategy, + ListNodesStrategy listNodesStrategy, + GroupNamingConvention.Factory namingConvention, + @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, + CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory, + AzureComputeApi api) { + super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor, + customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory); + this.api = checkNotNull(api, "api cannot be null"); + checkNotNull(userExecutor, "userExecutor cannot be null"); + } + + @Override + public Map<?, ListenableFuture<Void>> execute(String group, int count, Template template, + Set<NodeMetadata> goodNodes, Map<NodeMetadata, Exception> badNodes, + Multimap<NodeMetadata, CustomizationResponse> customizationResponses) { + + ResourceGroupApi resourceGroupApi = api.getResourceGroupApi(); + ResourceGroup resourceGroup = resourceGroupApi.get(group); + final String location = template.getLocation().getId(); + final String resourceGroupName; + + if (resourceGroup == null){ + + final Map<String, String> tags = ImmutableMap.of("description", "jClouds managed VMs"); + resourceGroupName = resourceGroupApi.create(group, location, tags).name(); + } else { + resourceGroupName = resourceGroup.name(); + } + + Map<?, ListenableFuture<Void>> responses = super.execute(resourceGroupName, count, template, goodNodes, badNodes, + customizationResponses); + + return responses; + } + +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/03f72d5e/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeProperties.java ---------------------------------------------------------------------- diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeProperties.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeProperties.java index 48188c4..48d6287 100644 --- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeProperties.java +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeProperties.java @@ -33,4 +33,12 @@ public class AzureComputeProperties { 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"; + + public static final String DEFAULT_IMAGE_LOGIN = "jclouds.azurecompute.arm.defaultimagelogin"; + + public static final String TIMEOUT_RESOURCE_DELETED = "jclouds.azurecompute.arm.timeout.resourcedeleted"; + } http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/03f72d5e/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceProviderMetaData.java ---------------------------------------------------------------------- diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceProviderMetaData.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceProviderMetaData.java new file mode 100644 index 0000000..84526b9 --- /dev/null +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceProviderMetaData.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.azurecompute.arm.domain; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; +import org.jclouds.json.SerializedNames; + +import java.util.List; + +@AutoValue +public abstract class ResourceProviderMetaData { + + public abstract String resourceType(); + + public abstract List<String> locations(); + + public abstract List<String> apiVersions(); + + @SerializedNames({"resourceType", "locations", "apiVersions"}) + public static ResourceProviderMetaData create(final String resourceType, final List<String> locations, final List<String> apiVersions) { + ResourceProviderMetaData.Builder builder = ResourceProviderMetaData.builder() + .resourceType(resourceType) + .locations(locations == null ? ImmutableList.<String>of() : ImmutableList.copyOf(locations)) + .apiVersions(apiVersions == null ? ImmutableList.<String>of() : ImmutableList.copyOf(apiVersions)); + + return builder.build(); + } + + public static Builder builder() { + return new AutoValue_ResourceProviderMetaData.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder resourceType(String resourceType); + + public abstract Builder locations(List<String> locations); + + public abstract Builder apiVersions(List<String> apiVersions); + + abstract List<String> locations(); + + abstract List<String> apiVersions(); + + abstract ResourceProviderMetaData autoBuild(); + + public ResourceProviderMetaData build() { + locations(locations() != null ? ImmutableList.copyOf(locations()) : ImmutableList.<String>of()); + apiVersions(apiVersions() != null ? ImmutableList.copyOf(apiVersions()) : ImmutableList.<String>of()); + return autoBuild(); + } + } +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/03f72d5e/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMDeployment.java ---------------------------------------------------------------------- diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMDeployment.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMDeployment.java index 2504409..6909a7b 100644 --- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMDeployment.java +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMDeployment.java @@ -26,4 +26,6 @@ public class VMDeployment { public List<PublicIPAddress> ipAddressList; public VirtualMachineInstance vm; + + public VirtualMachine virtualMachine; } http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/03f72d5e/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMHardware.java ---------------------------------------------------------------------- diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMHardware.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMHardware.java new file mode 100644 index 0000000..d338327 --- /dev/null +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMHardware.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.azurecompute.arm.domain; + +import com.google.auto.value.AutoValue; + +/** + * A VM Size that is available in a region for a given subscription. + * + * @see <a href="https://msdn.microsoft.com/en-us/library/azure/mt269440.aspx" >api</a> + */ +@AutoValue +public class VMHardware { + + /** + * The name of the VM size. + */ + public String name; + + /** + * The number of cores that are available in the VM size. + */ + public Integer numberOfCores; + + /** + * Specifies the size in MB of the OS Disk. + */ + public Integer osDiskSizeInMB; + + /** + * The size of the resource disk. + */ + public Integer resourceDiskSizeInMB; + + /** + * Specifies the available RAM in MB. + */ + public Integer memoryInMB; + + /** + * Specifies the maximum number of data disks that can be attached to the VM size. + */ + public Integer maxDataDiskCount; + + /** + * Specifies the location of the HW resource + */ + public String location; + + /** + * Specifies if this HW is globally available + */ + public boolean globallyAvailable; +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/03f72d5e/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java ---------------------------------------------------------------------- diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java new file mode 100644 index 0000000..ccfb05a --- /dev/null +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.azurecompute.arm.domain; + +import com.google.auto.value.AutoValue; + +@AutoValue +public class VMImage { + + /** + * The publisher of the image reference. + */ + public String publisher; + + /** + * The offer of the image reference. + */ + public String offer; + + /** + * The sku of the image reference. + */ + public String sku; + + /** + * The version of the image reference. + */ + public String version; + + /** + * The location from where Image was fetched + */ + public String location; + + /** + * Specifies if this image is globally available + */ + public boolean globallyAvailable; +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/03f72d5e/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachine.java ---------------------------------------------------------------------- diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachine.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachine.java index 71387e6..3013543 100644 --- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachine.java +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachine.java @@ -64,6 +64,6 @@ public abstract class VirtualMachine { public static VirtualMachine create(final String id, final String name, final String type, final String location, @Nullable final Map<String, String> tags, VirtualMachineProperties properties) { - return new AutoValue_VirtualMachine(id, name, location, type, tags == null ? null : ImmutableMap.copyOf(tags), properties); + return new AutoValue_VirtualMachine(id, name, type, location, tags == null ? null : ImmutableMap.copyOf(tags), properties); } } http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/03f72d5e/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ResourceProviderApi.java ---------------------------------------------------------------------- diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ResourceProviderApi.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ResourceProviderApi.java new file mode 100644 index 0000000..e3d38b8 --- /dev/null +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ResourceProviderApi.java @@ -0,0 +1,57 @@ +/* + * 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 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 javax.inject.Named; +import javax.ws.rs.Consumes; +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; + +/** + * The Azure Resource Provider API provides information about a resource provider and its supported resource types. + * + * @see <a href="https://msdn.microsoft.com/en-us/library/azure/dn790534.aspx">docs</a> + */ +@Path("/providers") + +@QueryParams(keys = "api-version", values = "2015-01-01") +@RequestFilters(OAuthFilter.class) +@Consumes(MediaType.APPLICATION_JSON) +public interface ResourceProviderApi extends Closeable { + + @Named("providers:get") + @GET + @Path("/{namespace}") + @SelectJson("resourceTypes") + @Fallback(NullOnNotFoundOr404.class) + @Nullable + List<ResourceProviderMetaData> get(@PathParam("namespace") String namespace); +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/03f72d5e/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/CleanupResources.java ---------------------------------------------------------------------- diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/CleanupResources.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/CleanupResources.java new file mode 100644 index 0000000..2b6a18e --- /dev/null +++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/CleanupResources.java @@ -0,0 +1,107 @@ +/* + * 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 static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED; + +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.compute.reference.ComputeServiceConstants; +import org.jclouds.logging.Logger; + +import com.google.common.base.Function; + +import java.net.URI; + +@Singleton +public class CleanupResources implements Function<String, Boolean> { + + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + protected final AzureComputeApi api; + private Predicate<URI> nodeTerminated; + private Predicate<URI> resourceDeleted; + + @Inject + public CleanupResources(AzureComputeApi azureComputeApi, + @Named(TIMEOUT_NODE_TERMINATED) Predicate<URI> nodeTerminated, + @Named(TIMEOUT_RESOURCE_DELETED) Predicate<URI> resourceDeleted) { + + this.api = azureComputeApi; + this.nodeTerminated = nodeTerminated; + this.resourceDeleted = resourceDeleted; + } + + @Override + public Boolean apply(String id) { + + logger.debug("Destroying %s ...", id); + String storageAccountName = id.replaceAll("[^A-Za-z0-9 ]", "") + "storage"; + int index = id.lastIndexOf("-"); + String group = id.substring(0, index); + + // Delete VM + URI uri = api.getVirtualMachineApi(group).delete(id); + if (uri != null){ + boolean jobDone = nodeTerminated.apply(uri); + + if (jobDone) { + // Delete storage account + api.getStorageAccountApi(group).delete(storageAccountName); + + // Delete NIC + uri = api.getNetworkInterfaceCardApi(group).delete(id + "nic"); + if (uri != null){ + jobDone = resourceDeleted.apply(uri); + if (jobDone) { + + // Delete deployment + uri = api.getDeploymentApi(group).delete(id); + jobDone = resourceDeleted.apply(uri); + if (jobDone) { + // Delete public ip + boolean ipDeleteStatus = api.getPublicIPAddressApi(group).delete(id + "publicip"); + + // Delete Virtual network + boolean vnetDeleteStatus = api.getVirtualNetworkApi(group).delete(group + "virtualnetwork"); + return ipDeleteStatus && vnetDeleteStatus; + + } else { + return false; + } + } else { + return false; + } + } else { + return false; + } + } else { + return false; + } + } else { + return false; + } + } +}
